Journal Simuler un clic avec libevdev et uinput

Posté par  . Licence CC By‑SA.
70
2
sept.
2021

Sommaire

Préambule

Samedi 7 août, 14h UTC+2 : une pluie de tous les enfers se déchaîne. Il pleut tout l’après-midi, mais c’est la tempête surtout pendant une demi heure. Le sol est inondé. Les gens courent, l’imper sur lequel je comptais jette l’éponge, mon téléphone pas étanche dans la poche de l’imper pas étanche est mouillé et c’est le drame : il ne s’allume plus.

Dimanche 8 août. Le téléphone refonctionne (son module wifi et Bluetooth démarre bien quand bon lui semble, mais il finira par refonctionner normalement quelques jours plus tard. Ouf).

… mais une bande de l’écran ne répond plus au tactile. Cette bande correspond pile poil à la barre d’état de l’environnement graphique, Phosh. C’est la même qu’on trouve aussi sur iOS et Android, rien de remarquable : on en a besoin pour accéder aux différentes fonctionnalités activables et désactivables et il n’y a guère d’autres interactions possibles sur cette barre. Vous connaissez certainement.

Bon, c’est chiant, mais en même temps, je n’ai aucune envie de changer l’écran pour si peu. Alors, que faire ?

Problème et solution

Sur Phosh, la seule interaction possible sur cette barre est un clic, pour la dérouler. L’idée n’a pas tardé à arriver : on pourrait simuler un clic déclenché par une autre interaction, par exemple en posant trois doigts n’importe où sur l’écran. Il se trouve que le téléphone tourne sur une Debian, adaptée pour mobile (Mobian), tout ce qu’il y a de plus classique à part ça. On doit bien pouvoir faire quelque chose sur un tel système bidouillable sans devoir télécharger des centaines de mégas de SDK et accepter des licences pénibles, non ?

Bien sûr que oui, sinon ce journal n’existerait pas !! Phosh est basé sur Wayland, donc les solutions basées sur un serveur X11 comme xdotools sont très vite écartées. Il va falloir taper plus bas dans la pile logicielle. Il nous faudra également une manière de surveiller les tapes tactiles pour détecter quand trois doigts sont appuyés sur l’écran.

libevdev – récupérer les évènements des périphériques d’entrée

Une recherche « Komen kon fé pour détecté les tapes ? » me mène rapidement sur cet article du blog de Peter Hutterer, alias Who-T, de chez Red Hat. Peter, c’est le monsieur input de l’écosystème libre. La référence ultime. Quand tu tombes sur son blog, tu sais que tu ne vas pas lire de conneries. Il a donné une présentation super intéressante à la linux.conf.au 2020 "Write a single library to handle all input devices, it'll be easy" they said…, que je vous recommande vivement si vous comprenez l’anglais. C’est assez accessible et beaucoup plus intéressant que ça en a l’air. D’ailleurs, il y annonce qu’il cherche désespérément des gens pour travailler avec lui dans le domaine et que le bus factor est dangereusement proche de 1, mais que ce n’est pas très sexy comme domaine, parce qu’il faut péniblement prendre en charge et tester manuellement chaque matériel avec ses spécificités pour que le reste du monde n’ait pas besoin de s’emmerder avec ça et que tout fonctionne out of the box, et que les gens préfèrent généralement travailler sur d’autres trucs. Donc si ce journal suscite des vocations, ne vous censurez pas, contactez-le…

Bref, il nous raconte que :

libevdev is a wrapper library to access /dev/input/eventX devices and provide their events through a C API.

Traduction :

libevdev est une bibliothèque qui enrobe les périphériques /dev/input/eventX et fournit leurs évènements à travers une API C.

Parfait, ça ! Bon, c’était en 2013, mais tout fonctionne encore pareil. Ouf !

Why use a library though? The kernel interface is relatively simple, but it has a few pitfalls. For one, device data is accessed through ioctl(2) and can cause weird bugs [1]. Second, not all events work in the same way. e.g. EVIOCGABS doesn't work the same for multi-touch axes, simply because the slot protocol has different semantics than the normal EV_ABS protocol. EV_REP has different handling as EV_ABS, EV_SYN is a special case anyway, etc. libevdev tries to avoid having to think about the differences and does sanity checks for the various calls.

Traduction (romancée) :

Mais pourquoi utiliser une bibliothèque ? L’interface noyau est relativement simple, mais elle a quelques soucis. Ça va être chiant, franchement on s’est embêtés à faire une bibliothèque toute propre qui uniformise tous vos affreux périphériques tous les plus différents les uns que les autres, utilisez ça si vous ne voulez pas finir dans une pièce blanche avec une camisole. Pitié, on sait de quoi on parle, on s’est sacrifiés pour vous alors maintenant, faites-nous plaisir et utilisez libevdev.

Bon, ça a l’air bien libevdev, on va utiliser ça. Peter nous explique en détail comment faire dans son article en s’appuyant sur cet exemple simple. Pour votre plaisir je vais le faire de ma manière ici.

Ouverture du périphérique et réception des évènements tactiles

Commençons donc par inclure les bons entêtes, et on va ouvrir le périphérique qui correspond à la dalle tactile de mon téléphone et écouter les évènements qui arrivent :

// (Tout le code C dans ce journal est copyright 2013 Red Hat, Inc, copyright 2021 moi, licence MIT)
#include <stdbool.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <libevdev/libevdev.h>

int main(int argc, char **argv)
{
    int rc = 1;

    struct libevdev *dev = NULL;

    int fd = open("/dev/input/by-path/platform-1c2ac00.i2c-event", O_RDONLY);

    if (fd < 0) {
        perror("Failed to open device");
        goto out;
    }

    rc = libevdev_new_from_fd(fd, &dev);

    do {
        struct input_event ev;
        rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL|LIBEVDEV_READ_FLAG_BLOCKING, &ev);
        if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
            handle_event(&ev);
        }
    } while (rc == LIBEVDEV_READ_STATUS_SYNC || rc == LIBEVDEV_READ_STATUS_SUCCESS || rc == -EAGAIN);

    if (rc != LIBEVDEV_READ_STATUS_SUCCESS && rc != -EAGAIN) {
        fprintf(stderr, "Failed to handle events: %s\n", strerror(-rc));
    } else {
        rc = 0;
    }

out:
    if (fd > 0) {
        close(fd);
    }

    if (dev != NULL) {
        libevdev_free(dev);
    }

    return rc;
}

Décortiquons tout ça :

  1. on ouvre le périphérique qui correspond à la dalle tactile avec open
  2. on passe le périphérique à libevdev pour pouvoir l’utiliser à travers la bibliothèque, avec libevdev_new_from_fd
  3. on boucle sur les évènements qui arrivent, en récupérant le prochain évènement avec libevdev_next_event (appel bloquant)
  4. on passe ces évènements à une fonction handle_event que nous nous apprêtons à construire

Il y a toute la gestion des erreurs, avec l’entier rc qui contient le code de retour, initialisé à 1 comme ça par défaut on retourne une erreur et on le passera à 0 quand tout se sera bien passé. On groupe le nettoyage à la fin de la fonction, accessible par des goto (en cas d’erreur) avec l’étiquette out qui va bien.

Le fonctionnement normal du programme est de ne jamais s’arrêter de lui-même. On ne compte pas débrancher l’écran tactile en cours d’utilisation. On attend continuellement des évènements à traiter.

Le programme peut être lancé en tant qu’utilisateur simple, puisqu’un utilisateur simple peut accéder en lecture aux périphériques d’entrée. D’ailleurs, si vous vous disiez que Wayland vous protégeait des keyloggers parce que ça isole correctement les applications entre elles, eh bien c’est raté, la couche d’en dessous se charge de donner les accès.

Bon, alors, on se la fait cette gestion des évènements ??

Eh ben oui, allons-y…

Gestion des évènements

Alors là, on implémente la fonction handle_event qui manque dans la section précédente. On cherche à repérer le moment où trois doigts sont posés sur l’écran, ni plus, ni moins.

static int handle_event(struct input_event *ev, struct libevdev_uinput* uidev)
{
    static int max_finger_id = 0;
    static bool pressed = false;
    static int must_click_on_btn_release = false;

    switch (ev->type) {
        case EV_ABS:
            if (ev->code == ABS_MT_SLOT) {
                max_finger_id = max(max_finger_id, ev->value);
            }
            break;

        case EV_KEY:
            if (ev->code == BTN_TOUCH) {
                pressed = ev->value;
            }
            break;

        case EV_SYN:
            if (max_finger_id == 2  && pressed) {
                must_click_on_btn_release = true;
            } else if (must_click_on_btn_release && !pressed) {
                simclick();
                must_click_on_btn_release = false;
            }

            max_finger_id = 0;
            break;
    }

    return 0;
}

La structure input_event qu’on reçoit a trois champs qui nous intéressent : type, code et value. Le premier donne le type général de l’évènement, le deuxième spécifie plus précisément et le troisième est une info qui dépend de l’évènement (par exemple, quelle touche de clavier a été enfoncée).

Trois évènements nous concernent :

  • le type EV_ABS, avec le code MT_SLOT. ABS, c’est pour absolu. Ça concerne les évènements qui ont des coordonnées absolues comme les écrans tactiles, à l’opposé des évènements relatifs comme les déplacements de souris. MT_SLOT, pour mutltitouch slot, permet de pister un doigt sur un écran tactile. Chaque doigt a son numéro, par ordre d’arrivée sur l’écran, en commençant par 0, puis 1, puis… vous avez compris. Quand vous déplacez vos doigts sur l’écran, ça va générer plein d’évènements mais chaque doigt aura toujours le même numéro (slot). C’est bien pratique. Vous imaginez, s’il fallait re-déduire le numéro de chaque doigt, évènement par évènement ? Heureusement que c’est fait pour nous !!
  • le type EV_KEY, avec le code BTN_TOUCH. BTN pour button. Quand vous enfoncez un ou des doigt(s), ça génère un évènement BTN_TOUCH avec une valeur true, et quand vous le(s) relâchez, ça génère un évènement avec une valeur false.
  • le type EV_SYN. C’est un évènement particulier, de synchronisation. Quand vous faites quelque chose sur votre écran (ou tout autre périphérique d’entrée), ça peut générer plusieurs évènements, pour la même action. Par exemple : « il s’est passé quelque chose avec le doigt 1 (EV_ABS). Il a été retiré de l’écran (EV_KEY). Ces évènements seront alors regroupés entre deux évènements de synchronisation EV_SYN.

Vous vous dites peut-être alors qu’il va falloir stocker tout un état entre plusieurs évènements, au moins jusqu’au prochain « EV_SYN », voire plus, pour réagir quand on a assez d’info. J’ai pour cela choisi d’utiliser des variables statiques, qui persistent entre deux appels de la fonction handle_event. Ultra pratique. C’est comme des globales, mais pas accessibles depuis les autres fonctions. Ça rend la fonction totalement impure et il faut faire attention, ça rend potentiellement les tests unitaires pour cette fonction compliqués (je suis tombé sur cet échange « amusant » avec un gars qui doit tester un code d’avion qu’il ne peut pas vraiment modifier en rédigeant le journal, il y a des astuces intéressantes chez IBM), mais en même temps ça colle parfaitement avec ce que j’ai envie de faire et je n’ai pas prévu de faire de tests unitaires.

Bref, en gros, ça fonctionne comme ça :

  • quand on reçoit un numéro de doigt on enregistre son numéro (slot), s’il est plus grand que le numéro qu’on connait déjà.
  • quand un (des) doigt(s) est (sont) appuyé(s) ou relâché(s), on stocke ça dans pressed
  • quand la fin d’un bloc d’évènements arrive :
    • si on réalise que exactement 3 doigts on été pressés (max_finger_id == 2 && pressed), on enregistre le souhait de générer un clic quand les doigts sont relâchés (must_click_on_btn_release);
    • si on réalise que tous les doigts ont été relâchés et qu’on souhaitait générer le clic, on le génère en appelant la fonction simclick et on oublie le souhait de générer un clic
    • on réinitialise le numéro de doigts max.

Notes :

  • en jouant avec libevdev, on peut avoir l’impression qu’il manque des évènements. En fait, si on s’attendait à avoir un évènement mais que celui-ci aurait eu la même valeur que le dernier évènement reçu du même type et du même code, on ne le reçoit pas une nouvelle fois. Ainsi, si vous voulez écrire des interactions compliquées, il ne faudrait pas réinitialiser votre état après chaque évènement EV_SYN, ce serait une erreur. Il n’y a probablement qu’en pratiquant et en se payant le mur soi-même que ça devient clair.
  • Pourquoi attendre que les doigts soient relâchés ? Pourquoi ne pas simplement générer un clic dès qu’on voit que tous les doigts ont été pressés ? Eh bien parce que c’est plus intuitif à l’utilisation. Si vous alliez poser un 4ᵉ doigt par exemple, trop tard, vous avez déjà généré le clic qui correspond à 3 doigts (or, je vous montre une version simplifiée de handle_event, et j’ai effectivement une gestion différente pour un 4ᵉ doigt). Et aussi, à cause d’un problème dont je parle dans la section suivante.

Notre détection des 3 doigts est maintenant complète. Youpeee ! C’est déjà ça ! Vous pourriez vous arrêter là. Si vous vouliez par exemple exécuter une commande quand trois doigts sont appuyés, vous avez gagné. Il suffit d’appeler system ou fork + une version de exec.

Mais nous, on veut simuler un clic, alors c’est parti.

uinput – générer des évènements

J’apprends rapidement que pour simuler des clics (donc produire des évènements d’entrée « fake »), on peut utiliser l’interface du noyau Linux uinput. Pour citer Who-T :

uinput is the kernel interface to create evdev devices that, for most purposes, look the same as real devices

Traduction :

uinput est l’interface noyau pour créer des périphériques evdev qui, pour la plupart des situations, ressemblent comme deux gouttes d’eau à des périphériques réels

Très bien !

On continue à lire :

As the evdev interface, the uinput interface requires you to handle a few structs and ioctls, not necessarily in an obvious way. libevdev wraps that for you.

Traduction :

Comme pour l’interface evdev, l’interface uinput vous demande de gérer quelques structures et ioctls, pas forcément de manière évidente. libevdev vous enrobe tout ça pour vous.

Traduction :

Rendez-vous service, utilisez libevdev-uinput. Sérieux.

Bon, très bien, nous allons utiliser libevdev-uinput pour simuler un clic.

Comme pour la section précédente, Peter fait une très bonne présentation sur son article, et je vais vous la faire à ma sauce. Les exemples d’utilisations de libevdev et libevdev-uinput ne courent pas spécialement les rues d’internet alors ça ne peut pas faire trop de mal.

On peut créer un périphérique d’entrée virtuel de zéro, en spécifiant toutes ses caractéristiques, et notamment les types d’évènement qu’il est capable de générer. Mais en fait, il y a une manière plus simple de faire : il est possible de copier un périphérique existant, tout simplement. Et ça tombe bien, parce qu’on en a déjà un sous la main qu’on utilise déjà : c’est l’écran tactile. En plus, ça permettra vraiment de simuler exactement ce qu’il se serait passé si on avait nous-même touché l’écran tactile au bon endroit (c’est-à-dire, là où il est mort, si vous suivez), et Phosh n’y verra que du feu.

On va reprendre la ligne qui charge notre dalle tactile :

    rc = libevdev_new_from_fd(fd, &dev);

Le périphérique est chargé dans la structure dev si l’opération a réussi.

On va lui donner un nom à l’aide de la fonction libevdev_set_name et le copier dans une nouvelle structure semblable, uidev, à l’aide de la fonction libevdev_uinput_create_from_device.

On déclare la structure au début de la fonction main avant toute utilisation de goto :

    struct libevdev_uinput* uidev = NULL;
    libevdev_set_name(dev, "Fake device clicking on the top of the screen");

    rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
    if (rc < 0) {
        fprintf(stderr, "Failed to create fake device (%s)\n", strerror(-rc));
        goto out;
    }

Faudra pas oublier de libérer le périphérique dans la section out de main:

    if (uidev != NULL) {
        libevdev_uinput_destroy(uidev);
    }

On va passer à uidev à handle_event pour qu’elle puisse la passer à simclick:

  • handle_event(&ev); devient handle_event(&ev, uidev);
  • static int handle_event(struct input_event *ev) devient static int handle_event(struct input_event *ev, struct libevdev_uinput* uidev)
  • simclick(); devient simclick(uidev);

La fonction simclick est assez bête. J’ai pris le programme d’exemple de Peter, je l’ai compilé, je l’ai lancé et j’ai appuyé sur mon écran tactile. J’ai pu voir tous les évènements qui étaient générés et j’ai bêtement copié tout ça en adaptant les coordonnées de l’évènement pour que ça clique au bon endroit. Petite subtilité avec le tracking id pour discerner les évènements générés :

static void simclick(struct libevdev_uinput* uidev)
{
    static int tracking_id = 1;
    int x = 15;
    int y = 15;
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_SLOT, 0);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, tracking_id++);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_POSITION_X, x);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_POSITION_Y, y);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_TOUCH_MAJOR, 22);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_WIDTH_MAJOR, 22);
    libevdev_uinput_write_event(uidev, EV_KEY, BTN_TOUCH, 1);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_X, x);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_Y, y);
    libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
    libevdev_uinput_write_event(uidev, EV_ABS, ABS_MT_TRACKING_ID, -1);
    libevdev_uinput_write_event(uidev, EV_KEY, BTN_TOUCH, 0);
    libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
}

… C’est… laborieux, mais pas très compliqué.

Et voilà, on a fini !
Si vous lancez le programme, si tout va bien, vous pourrez voir votre périphérique virtuel apparaitre dans la liste produite par la commande libinput list-devices :

Device:           Goodix Capacitive TouchScreen
Kernel:           /dev/input/event2
Group:            3
Seat:             seat0, default
Capabilities:     keyboard touch 
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      identity matrix
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   n/a
Rotation:         n/a

…

Device:           Fake device clicking on the top of the screen
Kernel:           /dev/input/event6
Group:            6
Seat:             seat0, default
Capabilities:     keyboard touch 
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      identity matrix
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   n/a
Rotation:         n/a

Les plus attentifs et les plus attentives auront remarqué qu’on ne supprime jamais les évènements initiaux correspondant aux trois doigts appuyés sur l’écran tactile. Et, oui, il s’agit d’une limitation. Je ne sais pas (encore) faire. Il y a peut-être moyen d’enregistrer notre périphérique virtuel et de bloquer le vrai périphérique et de filtrer les bons évènements. Il ne faut probablement pas tous les filtrer, mais peut-être juste les évènements BTN_TOUCH par exemple si ça suffit (peut-être pas). Sinon, ça pourrait avoir des effets de bords indésirables. Donc oui, si je ne fais pas attention, je déclenche des clics dans les applications actuellement affichées sur l’écran.

Note : contrairement à juste capter des évènements, simuler un périphérique nécessite d’être root (ou peut-être d’appartenir au bon groupe, mais je n’ai pas trop creusé).

Compilation et installation

C’est pas le tout, mais maintenant, il faut que le programme tourne et se lance au démarrage. Déjà, il faut installer le paquet de développement de libevdev (libevdev-dev chez les debianeux, libevdev-devel chez les rpmistes).

Puis, on compile et on installe :

gcc simclick.c $(pkg-config --libs --cflags libevdev) -o simclick 
sudo cp simclick /usr/local/bin/simclick

On fait un service systemd :

cat > /etc/systemd/system/simclick.service <<EOF
[Unit]
Description=Simulate top click using three fingers
ConditionFileIsExecutable=/usr/local/bin/simclick
After=phosh.service
[Service]
Type=simple
ExecStart=/usr/local/bin/simclick
RemainAfterExit=no
[Install]
WantedBy=multi-user.target
EOF

(je réalise qu’il faudra adapter ce After=phosh.service, d’ailleurs, et peut-être trouver une autre cible pour le rendre plus générique, là ça le rend spécifique à Phosh)

Et au redémarrage, ça marche tout seul.

Future work

(J’aurais pu titrer « Pistes d’amélioration » mais allez, ça me fait plaisir de nommer cette section comme ça.)

Pour l’instant j’utilise Phosh, mais je compte à plus ou moins court terme passer à Plasma Mobile, qui est d’ailleurs maintenant l’environnement par défaut du PinePhone (quelques trucs bloquants mais de moins en moins, et tant mieux, parce ça me convient mieux. Mais du coup, l’interaction sur la barre d’état pour la dérouler est vraiment un glisser vers le bas comme sous Android, donc la fonction simclick sera autrement plus compliquée. Mais ça ne devrait pas être trop difficile à faire, surtout qu’on peut enregistrer les évènements et presque les copier bêtement dans le code.

On pourrait s’amuser à rendre l’interaction plus intuitive en permettant demandant à ce que l’utilisateur fasse un glissé, peut-être avec deux doigts seulement. On peut imaginer tout un tas d’interactions pratique qui ne sont pas fournies par l’environnement. Il faut cependant trouver le moyen de garder la fonction handle_event lisible et claire, parce que pour avoir un peu tester, ça devient vite le bronx. Ou organiser autrement : faire une fonction par interaction. Pas toujours simple parce que parfois il y a des conflits. Tout bêtement, après un glissé, vous ne voulez pas déclencher l’action déclenchée par un touché simple.

Bon, on ne va pas se mentir, tout ça, c’est pour susciter votre esprit bidouilleur, mais restons les pieds sur terre : m’amuser avec des interactions tactiles sur le téléphone passera certainement après un tas de trucs que j’ai envie de faire donc il est peu probable que j’y passe un temps fou. À la base, c’est juste pour contourner cette zone morte de mon écran :-)

Conclusion

J’espère que vous avez apprécié ce journal. Si vous avez des questions ou des remarques, n’hésitez pas. En tout cas, ça fait un mois que j’utilise ce petit programme, sans accros ! Ça tourne et ça ne plante pas (ou, en tout cas, moins fréquemment que le téléphone lui-même !), et je m’y suis fait, j’aime plutôt bien taper sur l’écran avec trois doigts pour dérouler ce menu !

Références :

  • # différence avec libinput?

    Posté par  . Évalué à 7.

    Tout est dans le titre. Il me semble bien que ces 2 solutions sont concurrentes. J'ai souvenir d'avoir utilisé libinput, pour lire des évènements, par contre, pas pour les injecter. C'était aussi assez simple, surprenant pour des outils si bas niveau.
    Si j'en crois la liste des paquets qui fournissent xorg-driver-input sur ma debian, c'est vraiment très probable qu'ils fassent la même chose.
    Je n'émets aucun jugement de valeur, je n'avais pas trop creusé le sujet à l'époque, il fallait que j'implémente la chose rapidement…

    • [^] # Re: différence avec libinput?

      Posté par  . Évalué à 10.

      À première vue, libinput est une couche au dessus de evdev (en tout cas l'interface noyau, peut-être de la bibliothèque libevdev). Elle s'appuie sur tout une base de données de périphériques pour rectifier les quirks de chacun d'eux. Elle fait aussi un pré-traitement pour générer des évènements auxquels on s'attend, par exemple générer un clic droit quand on tape avec deux doigts sur un touchpad, générer des déplacements relatifs en gérant l'accélération, des évènements de défilement quand on glisse deux doigts vers le haut/bas, etc: elle fournit une interprétation « lissée » des évènements en provenance des périphériques d’entrée. Autre exemple : elle va couper les évènements d’un touchpad à l'intérieur d'un ordi portable quand son écran est rabattu, parce que sinon ça fait des évènements parasites sur certains modèles. Ce genre de détails auxquels on pourrait ne pas penser à première vue.

      À priori, c'est un peu trop haut niveau pour mon cas d'utilisation et ça se serait probablement mis en travers de mon chemin : j'avais vraiment besoin de récupérer les évènements tels quels sans post traitement logiciel particulier. Par contre, si j'avais eu besoin d'une interprétation de ces évènements, là libinput aurait été intéressante pour moi.

      Je doute également que libinput permet de créer des périphériques virtuels, à moins qu’elle fournisse un passe-droit vers libevdev pour ça, mais ça je n'ai pas vérifié, c'est peut-être possible et si quelqu'un a l'info, n’hésitez pas à compléter.

      Le dépôt du projet libinput : https://gitlab.freedesktop.org/libinput/libinput

      libinput is a library that provides a full input stack for display servers and other applications that need to handle input devices provided by the kernel.
      libinput provides device detection, event handling and abstraction to
      minimize the amount of custom input code the user of libinput needs to
      provide the common set of functionality that users expect. Input event
      processing includes scaling touch coordinates, generating
      relative pointer events from touchpads, pointer acceleration, etc.

      Traduction :

      libinput est une bibliothèque qui fournit une pile d'entrée pour les serveurs d'affichage et autres applications qui ont besoin de gérer les périphériques d’entrée fournis par le noyau.
      libinput fournit de la détection de périphérique, de la gestion d'évènements et de l'abstraction pour minimiser la quantité de code spécifique que l'utilisateur de libinput a besoin pour fournir une un socle de fonctionnalités communes auxquelles l'utilisateur s'attend. Le traitement des évènements inclut la mise à l'échelle des coordonnées tactiles, la génération d'évènements relatifs sur les touchpads, l'accélaration du pointeur, etc.

      Pour comparaison, on peut trouver le projet libevdev ici : https://gitlab.freedesktop.org/libevdev/libevdev

      Les deux projets sont vivants et maintenus par le même ensemble de personnes d'ailleurs.

  • # Introduction d'un bug ?

    Posté par  . Évalué à 10. Dernière modification le 03 septembre 2021 à 04:12.

    Bravo pour avoir sauvé ton téléphone !

    N'as-tu cependant pas introduit un bug dans le main ? J'ai l'impression que le source initial est :

        if (rc != LIBEVDEV_READ_STATUS_SUCCESS && rc != -EAGAIN) {
            fprintf(stderr, "Failed to handle events: %s\n", strerror(-rc));
    
        rc = 0;

    Que tu as réécrit en :

        if (rc != LIBEVDEV_READ_STATUS_SUCCESS && rc != -EAGAIN) {
           fprintf(stderr, "Failed to handle events: %s\n", strerror(-rc));
       } else {
           rc = 0;
       }

    Or l'absence du else a son importance il me semble !

    Mais j'ai peut-être raté une subtilité ("diff à vue de nez" :p)

    Matricule 23415

    • [^] # Re: Introduction d'un bug ?

      Posté par  . Évalué à 6. Dernière modification le 03 septembre 2021 à 06:58.

      Bien vu, d'ailleurs c'est un else que j'ai introduit hier en écrivant le journal.

      Je pense que la différence, c'est que dans le code original, si la récupération d'un évènement avec libevdev_next_event échoue, ça va quand-même retourner 0, alors qu'avec mon else, ça va retourner une erreur. Je trouve ce dernier comportement plus logique mais c'est discutable.

      Je n'ai pas vu le cas ne s'est pas produire jusqu'à maintenant.

      (D'ailleurs, je viens de voir un problème dans le journal, est-ce que l'équipe de modération veut-bien changer, dans les références, le lien derrière « Le code d’exemple de départ » par https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c s'il vous plait ?)

  • # Super article !

    Posté par  (site web personnel) . Évalué à 4. Dernière modification le 03 septembre 2021 à 10:31.

    Merci pour cet article qui me rappelle une fois où j'avais essayé de bidouiller libinput pour rajouter une fonctionnalité àlacon(R). J'avais même proposé un patch et reçu une réponse très sympa de Peter Hutterer qui a décidément l'air d'être un chic type !

    < humour >
    Par contre, j'espérais ne plus jamais entendre parler d'IBM RTRT de ma vie !
    </ humour >

  • # Le téléphone étanche du pauvre

    Posté par  . Évalué à 10.

    J'ai toujours un sac congélation 3L ou 5L propre et bien plié au fond de ma sacoche.
    ça prend vraiment pas de place. ça sert quasiment jamais mais ça sauve les papiers, le téléphone…

    Et ça marche aussi avec le sable.

    ça peut accessoirement servir de sac à vomi ou de sac à couches.
    ça peut même servir à nettoyer les plages.

    et il n'y a aucun brevet dessus ;)

    • [^] # Re: Le téléphone étanche du pauvre

      Posté par  . Évalué à 6.

      Ah yes, bonne idée. Je vais envisager cette solution. Merci beaucoup.

      (Ça a l'air d'être un peu comme la serviette à toujours avoir sur soi :-P)

    • [^] # Re: Le téléphone étanche du pauvre

      Posté par  . Évalué à 1. Dernière modification le 03 septembre 2021 à 13:55.

      Je valide le sac congélation.

      A noter que certain smartphones d'aujourd'hui sont à la norme IP67 (https://fr.wikipedia.org/wiki/Indice_de_protection)

      Testé le weekend dernier avec un Samsung tombé dans l'eau à la plage …

      • [^] # Re: Le téléphone étanche du pauvre

        Posté par  (site web personnel) . Évalué à 3.

        J'ai un Samsung S9,
        https://www.plusmobile.fr/fiches-techniques/samsung/galaxy-s9/sm-g960f/

        Il est IP68 : censé tenir 1h dans l'eau (pas testé, pas fou, d'façon j'ai un sac congélation pour les situations risquées 😁). Au moins c'est mieux que mon redmi note 10 précédent qui souffrait effectivement avec la pluie…

        • [^] # Re: Le téléphone étanche du pauvre

          Posté par  . Évalué à 0.

          C'est sur, personne n'a envie de tester.
          Mais ca reste des engins a tous faire super pratique.

          J'ai perdu un Oppo plutot haut de gamme pour changer une roue de bagnole sous la pluie et dans le noir (il me servait de lampe) :-/

          • [^] # Re: Le téléphone étanche du pauvre

            Posté par  (site web personnel, Mastodon) . Évalué à 2.

            J'ai vu des gens publier des (crash) tests de fou sur Youtube à une époque. Cela impliquait diverses chutes et casses (pour les modèles résistants) ainsi que la trempette (pour les modèles étanches et/ou insubmersibles). Me suis toujours demandé où ils trouvaient des sous à gaspiller mais je saluais le retour d'information avant de délier ma bourse.

            Pour la prochaine fois, tu penseras à le mettre sous film, en espérant que ça éclaire tout aussi bien quand on ne manie pas du cric dans l'obscurité. ^^

            “It is seldom that liberty of any kind is lost all at once.” ― David Hume

            • [^] # Re: Le téléphone étanche du pauvre

              Posté par  . Évalué à 3.

              Me suis toujours demandé où ils trouvaient des sous à gaspiller

              sponsors ?

              • [^] # Re: Le téléphone étanche du pauvre

                Posté par  (site web personnel, Mastodon) . Évalué à 2.

                Y a(vait) pas toujours la marque testée derrière, c'était même rare et ces gens testent des fabricants concurrents.
                Mais effectivement, j'ai oublié que les sponsors peuvent être autres et divers. Ils refont ce que faisaient des "journalistes" de revues/émissions spécialisées. Je creuserai la prochaine fois que je voudrai changer de périphérique.

                “It is seldom that liberty of any kind is lost all at once.” ― David Hume

              • [^] # Re: Le téléphone étanche du pauvre

                Posté par  (site web personnel) . Évalué à 3.

                Ou alors, si casser un téléphone coute 1000€, mais la vidéo va en rapporter 10000, ça vaut le coup…

                • [^] # Re: Le téléphone étanche du pauvre

                  Posté par  . Évalué à 3. Dernière modification le 15 octobre 2021 à 18:01.

                  Yep, d'ailleurs ça ne s'oppose pas, si la vidéo est sponsorisée par RasLeBolVPN ou JenPeuxPlusSchield c'est exactement ce qu'il va se passer :-)

                  (au fait, vous connaissez SponsorBlock ?)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.