Debian Debian-France Debian-Facile Debian-fr.org Forum-Debian.fr Debian ? Communautés

Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).

#1 14-01-2022 23:30:16

Tawal
Membre
Distrib. : Debian Stable à jour
Noyau : amd64
(G)UI : Xfce
Inscription : 25-02-2021

Alternative à xdotool mouse-click

Hello,

Je reposte ici un souci de bug concernant xdotool et sa commande behave . mouse-click.
Il est vieux et encore d'actualité : https://github.com/jordansissel/xdotool/issues/163

J'avais posté ce problème dans un autre sujet (qui a été résolu par contournement pour mon cas précis) :
https://debian-facile.org/viewtopic.php?id=30478
Mais bon, cette solution n'était pas si invisible que ça dans certains cas.

Bref, j'ai trouvé une sorte d'alternative à ce bug.
Elle passe par evtest.
La mise en place de l'alternative est décrite dans le commentaire "Pré-requis" du script (voir plus bas).

Edit: une version plus légère existe au #5.

J'ai appelé le script "xdo2" reproduisant le comportement de xdotool .... beahve . mouse-click ....
Son aide :

xdo2 --help


Usage :    xdo2   CMD_XDOTOOL
           xdo2   [-fipq] [-b BM] [-e EVENT]   CMD_XDOTOOL   +N|+@   CMD_XDO2
           xdo2   -h

Surcouche de 'xdotool'.
Palie au bug de 'xdotool ... behave . mouse-click ...'.
  CMD_XDOTOOL est la ligne de commande xdotool remplissant
    le WINDOW STACK sur laquelle la recherche de clic se fera ou
    une ligne de commande xdotool n'utilisant pas 'mouse-click'
    si utilisée seule.
  +N ou +@ remplace le 'behave %x mouse-click'
  +N indique le numéro N dans la pile WINDOW STACK
    sur lequel la recherche de clic se fera.
  +@ indique que la recherche de clic se fera sur toute
    la pile WINDOW STACK.
  CMD_XDO2 est une ligne de commande xdotool appliquée
    après la réussite du 'behave mouse-click'.
  $ utilisé dans CMD_XDO2 se refère à la fenêtre cliquée.
  @ utilisé dans CMD_XDO2 se refère à toute la pile WINDOW STACK.
  %N dans CMD_XDO2 pour rappeler la Nième fenêtre de la pile WINDOW STACK.
  $, @ ou %N est obligatoire dans CMD_XDO2 comme argument à toute commande
    xdotool se reférant à une fenêtre (option de commande comprise).
  Particularité de la commande 'exec' : Ne peut être utilisée qu'une seule fois
    dans CMD_XDO2, et doit se terminer par un caractère ; (protégé).

Options :
    -h, --help        Afficher cette aide et quitter.

    -b, --button BM   Sélectionner le(s) bouton(s) à prendre en compte.
                      B peut prendre les valeurs :
                          L : Bouton de gauche.
                          R : Bouton de droite.
                          M : Bouton du milieu (clic molette).
                      M peut prendre les valeurs :
                          0 : bouton relâché.
                          1 : bouton pressé.
                      BM peut aussi être une liste séparé par une virgule.
                      Exemple : -b L1,R0

    -e, --event N     Écouter l'event /dev/input/eventN.
                      N doit être un nombre ou une liste de nombres
                      séparés par une virgule. Ex : -e 8,9
                      Désactive la prise en charge des branchements à chaud.

    -f, --force       Forcer la prise en charge des branchements à chaud.
                      Utile qu'avec l'option '-e'.

    -i, --ignore      Désactiver la prise en charge des branchements à chaud.
                      Inutile avec l'option '-e'. Ignorée si '-f' est utilisée.

    -p, --pile        Afficher la pile WINDOW STACK de la commande de recherche.

    -q, --quit        One-shot : si clic réussi, exécute la commande et quitte.

Par défaut, écoute toutes les souris présentes et celles branchées à chaud.
Par défaut, Bouton Gauche Pressé pris en compte.

Fonctionnalités particulières :
  Possibilité d'écrire EOF dans la file des events pour arrêter le script.
    2 Méthodes :
      - Depuis, un processus enfant, le fd 4 est acessible :
            echo EOF >&4
      - Depuis l'extérieur, en écrivant dans le fichier /tmp/xdo2_PID_fifo,
        où PID est le pid de l'instance de ce script :
            echo EOF > /tmp/xdo2_PID_fifo
  La variable XDOclic est accessible aux processus enfants et détient la valeur
  du bouton cliqué : L0 = bouton gauche relâché, R1 = bouton droit pressé ...

Exemple :
   > xdo2 search --name ".*" +@ \
       exec --sync bash -c 'echo -n "$(date +%s) : "' \; getwindowname $
   1645371388 : Bureau
   1645371391 : xfce4-panel
   ^C>

Nécessités : xdotool, evtest, inotify-tools
                                   20-02-2022                            Tawal®©



Et le script :

#!/bin/bash


### Pré-requis :
#
#   Nécessite : xdotool (sudo apt install xdotool)
#               evtest  (sudo apt install evtest)
#               inotifywait (sudo apt install inotify-tools)
#
#   Puis 2 méthodes au choix :
#       1: Inscrire la commande /usr/bin/evtest dans /etc/sudoers de cette façon : sudo visudo
#              nom_user  ALL = NOPASSWD: /usr/bin/evtest
#          Modifier le script aux lignes 207 et 448 pour ajouter 'sudo' devant 'evtest'
#
#       2: Méthode utilsée dans le script :
#          Créer un groupe 'mouse-event' : sudo addgroup mouse-event
#          Créer une règle udev : /etc/udev/rules.d/99-MesMouses.rules contenant :
#              SUBSYSTEM=="input", SYMLINK=="input/by-path/*event-mouse", GROUP="mouse_event", MODE="0660"
#          Ajouter les utilisateurs pouvant utiliser ce script au groupe 'mouse_event' : sudo addgroup user mouse_event
#          Actif dès le prochain boot.
#          Pour une utilisation immédiate (déconnexion session) : sudo udevadm trigger
### ---


### Protection contre la collision de variables (pas d'accès à l'aide)
readarray -t _XDO_MC_col < <(set | grep "^_XDO_MC_.*=.*$")
if [ "${_XDO_MC_col[*]}" ]
then
    echo "${0##*/}: Export de variables interdites"
    printf "\t%s\n" "${_XDO_MC_col[@]}"
    echo "Vérifiez votre environnement !"
    exit 127
fi >&2


### Vérification de la présence des programmes requis
if [ "$1" != "-h" ] && [ "$1" != "--help" ]
then
    for _XDO_MC_i in xdotool evtest inotifywait
    do
        if ! hash "$_XDO_MC_i" 2>/dev/null
        then
            if [ "$1" = inotifywait ]
            then
                _XDO_MC_j="inotify-tools"
            else
                _XDO_MC_j="$_XDO_MC_i"
            fi
            echo "${0##*/}: Nécessite $_XDO_MC_i (sudo apt install $_XDO_MC_j)."
            _XDO_MC_quit="ON"
        fi
    done
    [ "$_XDO_MC_quit" ] && exit 1
fi >&2


### Fonctions
usage ()
{
    echo -e "Usage :    \E[1m${0##*/}   CMD_XDOTOOL"
    echo -e "           \E[1m${0##*/}   [-fipq] [-b BM] [-e EVENT]   CMD_XDOTOOL   +N|+@   CMD_XDO2\E[0m"
    echo -e "           \E[1m${0##*/}   -h\E[0m"
    echo
    echo -e "Surcouche de '\E[1mxdotool\E[0m'."
    echo -e "Palie au bug de '\E[3mxdotool ... behave . mouse-click ...\E[0m'."
    echo -e "  \E[1mCMD_XDOTOOL\E[0m est la ligne de commande \E[1mxdotool\E[0m remplissant"
    echo -e "    le \E[1mWINDOW STACK\E[0m sur laquelle la recherche de clic se fera ou"
    echo -e "    une ligne de commande \E[1mxdotool\E[0m n'utilisant pas '\E[3mmouse-click\E[0m'"
    echo    "    si utilisée seule."
    echo -e "  \E[1m+N\E[0m ou \E[1m+@\E[0m remplace le '\E[3mbehave %x mouse-click\E[0m'"
    echo -e "  \E[1m+N\E[0m indique le numéro \E[1mN\E[0m dans la pile \E[1mWINDOW STACK\E[0m"
    echo -e "    sur lequel la recherche de clic se fera."
    echo -e "  \E[1m+@\E[0m indique que la recherche de clic se fera sur toute"
    echo -e "    la pile \E[1mWINDOW STACK\E[0m."
    echo -e "  \E[1mCMD_XDO2\E[0m est une ligne de commande \E[1mxdotool\E[0m appliquée"
    echo -e "    après la réussite du '\E[3mbehave mouse-click\E[0m'."
    echo -e "  \E[1m$\E[0m utilisé dans \E[1mCMD_XDO2\E[0m se refère à la fenêtre cliquée."
    echo -e "  \E[1m@\E[0m utilisé dans \E[1mCMD_XDO2\E[0m se refère à toute la pile \E[1mWINDOW STACK\E[0m."
    echo -e "  \E[1m%N\E[0m dans \E[1mCMD_XDO2\E[0m pour rappeler la \E[1mN\E[0mième fenêtre de la pile \E[1mWINDOW STACK\E[0m."
    echo -e "  \E[1m$\E[0m, \E[1m@\E[0m ou \E[1m%N\E[0m est obligatoire dans \E[1mCMD_XDO2\E[0m comme argument à toute commande"
    echo -e "    \E[1mxdotool\E[0m se reférant à une fenêtre (option de commande comprise)."
    echo -e "  Particularité de la commande '\E[1mexec\E[0m' : Ne peut être utilisée qu'une seule fois"
    echo -e "    dans \E[1mCMD_XDO2\E[0m, et \E[1mdoit\E[0m se terminer par un caractère \E[1m;\E[0m (protégé)."
    echo
    echo    "Options :"
    echo    "    -h, --help        Afficher cette aide et quitter."
    echo
    echo -e "    -b, --button \E[1mBM\E[0m   Sélectionner le(s) bouton(s) à prendre en compte."
    echo -e "                      \E[1mB\E[0m peut prendre les valeurs :"
    echo -e "                          \E[1mL\E[0m : Bouton de gauche."
    echo -e "                          \E[1mR\E[0m : Bouton de droite."
    echo -e "                          \E[1mM\E[0m : Bouton du milieu (clic molette)."
    echo -e "                      \E[1mM\E[0m peut prendre les valeurs :"
    echo -e "                          \E[1m0\E[0m : bouton relâché."
    echo -e "                          \E[1m1\E[0m : bouton pressé."
    echo -e "                      \E[1mBM\E[0m peut aussi être une liste séparé par une virgule."
    echo    "                      Exemple : -b L1,R0"
    echo
    echo -e "    -e, --event \E[1mN\E[0m     Écouter l'event \E[3m/dev/input/event\E[0;1mN\E[0m."
    echo -e "                      \E[1mN\E[0m doit être un nombre ou une liste de nombres"
    echo    "                      séparés par une virgule. Ex : -e 8,9"
    echo    "                      Désactive la prise en charge des branchements à chaud."
    echo
    echo    "    -f, --force       Forcer la prise en charge des branchements à chaud."
    echo    "                      Utile qu'avec l'option '-e'."
    echo
    echo    "    -i, --ignore      Désactiver la prise en charge des branchements à chaud."
    echo    "                      Inutile avec l'option '-e'. Ignorée si '-f' est utilisée."
    echo
    echo -e "    -p, --pile        Afficher la pile \E[1mWINDOW STACK\E[0m de la commande de recherche."
    echo
    echo    "    -q, --quit        One-shot : si clic réussi, exécute la commande et quitte."
    echo
    echo    "Par défaut, écoute toutes les souris présentes et celles branchées à chaud."
    echo    "Par défaut, Bouton Gauche Pressé pris en compte."
    echo
    echo    "Fonctionnalités particulières :"
    echo -e "  Possibilité d'écrire \E[1mEOF\E[0m dans la file des events pour arrêter le script."
    echo    "    2 Méthodes :"
    echo -e "      - Depuis, un processus enfant, le \E[1mfd 4\E[0m est acessible :"
    echo -e "            \E[3mecho EOF >&4\E[0m"
    echo -e "      - Depuis l'extérieur, en écrivant dans le fichier \E[1m/tmp/${0##*/}_PID_fifo\E[0m,"
    echo -e "        où \E[1mPID\E[0m est le pid de l'instance de ce script :"
    echo -e "            \E[3mecho EOF > /tmp/${0##*/}_PID_fifo"
    echo -e "  La variable \E[1mXDOclic\E[0m est accessible aux processus enfants et détient la valeur"
    echo    "  du bouton cliqué : L0 = bouton gauche relâché, R1 = bouton droit pressé ..."
    echo
    echo    "Exemple :"
    echo    "   > ${0##*/} search --name \".*\" +@ \\ "
    echo    "       exec --sync bash -c 'echo -n \"\$(date +%s) : \"' \; getwindowname $"
    echo    "   1645371388 : Bureau"
    echo    "   1645371391 : xfce4-panel"
    echo    "   ^C>"
    echo
    echo    "Nécessités : xdotool, evtest, inotify-tools"
    printf  "%45s%37s\n" "20-02-2022" "Tawal®©"
    exit 0
}

err_opt ()
{   # Utilisation d'option non reconnue et sortie.
    echo "${0##*/}: Option non-reconnue : $1"
    exit 1
} >&2

err_opt_arg ()
{   # Erreur dans le format de l'argument de l'option '-b' ou '-e'.
    echo "${0##*/}: Erreur dans l'argument de l'option '$1' : $2"
    exit 1
} >&2

err_form_exec ()
{   # La commande 'exec' dans CMD_XDO2 ne se termine pas par un caractère ;
    echo -e "${0##*/}: Un caractère '\E[1m;\E[0m' protégé doit finir la commande '\E[1mexec\E[0m'."
    exit 1
} >&2

pids_child ()
{   # Liste les processus enfants du script.
    local i T
    readarray -t T < <(ps --no-headers --ppid "$1" -o pid)
    (("${#T[*]}")) && {
        for i in "${T[@]}"
        do
            pids_child $i   # $i not quoted to avoid head blank.
        done
        echo "${T[@]}"
    }
}

exit_trap ()
{   # Action à mener par la capture des signaux TERM HUP INT ABRT QUIT EXIT
    kill -15 $(pids_child $$) >/dev/null 2>&1
    exec 4>&-
    exec 5>&-
    rm -f "$1"
}

test_opt_b ()
{   # Vérification du format de l'argument de l'option '-b'.
    [[ $1 =~ ^[(L|M|R)(0|1),]*(L|M|R)(0|1)$ ]]
}

test_opt_e ()
{   # Vérification du format de l'argument de l'option '-e'.
    [[ $1 =~ ^([[:digit:]]*,)*[[:digit:]]*$ ]]
}

test_form_exec ()
{   # Vérification de la présence de ; pour terminer la commande 'exec'.
    local elem
    for elem in "$@"
    do
        if [ "$elem" = ";" ]
        then
            return 0
        fi
    done
    return 1
}

listen_event ()
{   # Écoute des event souris.
    local input
    for input in "$@"
    do
        evtest "$input" &
    done
}
###--- (Fin Fonctions)


### Gestion des options :
while getopts :b:e:fhipq-: _XDO_MC_opt
do
    case $_XDO_MC_opt in
        h) usage
           ;;

        b) test_opt_b "$OPTARG" || err_opt_arg "-b" "$OPTARG"
           _XDO_MC_opt_b="$OPTARG"
           ;;

        e) test_opt_e "$OPTARG" || err_opt_arg "-e" "$OPTARG"
           _XDO_MC_opt_e="$OPTARG"
           _XDO_MC_opt_i="ON"  # Activation option -i
           ;;

        f) _XDO_MC_opt_f="ON"
           ;;

        i) _XDO_MC_opt_i="ON"
           ;;

        p) _XDO_MC_opt_p="ON"
           ;;

        q) _XDO_MC_opt_q="ON"
           ;;

        -) case $OPTARG in
                help)
                    usage
                    ;;

                button)
                    test_opt_b ${!OPTIND}  || err_opt_arg "-b" ${!OPTIND}
                    _XDO_MC_opt_b="$OPTARG"
                    OPTIND=$((++OPTIND))
                    ;;

                event)
                    test_opt_e ${!OPTIND}  || err_opt_arg "-e" ${!OPTIND}
                    _XDO_MC_opt_e="$OPTARG"
                    _XDO_MC_opt_i="ON"   # Activation option -i
                    OPTIND=$((++OPTIND))
                    ;;

                force)
                    _XDO_MC_opt_f="ON"
                    ;;

                ignore)
                    _XDO_MC_opt_i="ON"
                    ;;

                pile)
                    _XDO_MC_opt_p="ON"
                    ;;

                quit)
                    _XDO_MC_opt_q="ON"
                    ;;

                *)
                    err_opt --${!OPTIND}
                    ;;
            esac
            ;;

        *)  err_opt -"$OPTARG"
            ;;
    esac
done
shift $((--OPTIND))


### Construction Regex matchant bouton cliqué.
if [ "$_XDO_MC_opt_b" ]
then
    readarray -td, _XDO_MC_Buttons < <(echo -n "$_XDO_MC_opt_b")
    _XDO_MC_Buttons=( "${_XDO_MC_Buttons[@]//L/BTN_LEFT.*value\ }" )
    _XDO_MC_Buttons=( "${_XDO_MC_Buttons[@]//M/BTN_MIDDLE.*value\ }" )
    _XDO_MC_Buttons=( "${_XDO_MC_Buttons[@]//R/BTN_RIGHT.*value\ }" )
    _XDO_MC_regex="$(IFS="|"; echo "${_XDO_MC_Buttons[*]/%/$}")"
else
    _XDO_MC_regex="BTN_LEFT.*value\ 1$"
fi


### Séparation CMD_XDOTOOL et CMD_XDO2 et Séparation de Comm_search en cas d'affichage demandé dans CMD_XDOTOOL.
_XDO_MC_Comm=( "$@" )
for _XDO_MC_i in "${!_XDO_MC_Comm[@]}"
do
    if [ "${_XDO_MC_Comm[$_XDO_MC_i]:0:1}" != "+" ]
    then
        if [ "${_XDO_MC_Comm[$_XDO_MC_i]:0:3}" = "get" ] && \
           [[ ! ${_XDO_MC_Comm[$_XDO_MC_i]} =~ ^getactivewindow$|^getwindowfocus$ ]] && \
           [ ! "${_XDO_MC_Comm_search[*]}" ]
        then
            _XDO_MC_Comm_search=( "${_XDO_MC_Comm[@]:0:$_XDO_MC_i}" )
        fi
        _XDO_MC_Comm_deb[$_XDO_MC_i]="${_XDO_MC_Comm[$_XDO_MC_i]}"
        continue
    else
        _XDO_MC_rais="${_XDO_MC_Comm[$_XDO_MC_i]#+}"
    fi
    shift $((_XDO_MC_i+1))
    break
done


### Commande sans 'mouse-click' (pas d'argument +N ou +@ dans la ligne de commande).
if [ ! "$_XDO_MC_rais" ]
then
    xdotool "${_XDO_MC_Comm[@]}"
    exit
fi
unset _XDO_MC_Comm


### Commande après clic
_XDO_MC_Comm_fin=( "$@" )


### Tableau des fenêtres trouvées.
if [ "${_XDO_MC_Comm_search[*]}" ]
then
    readarray -t _XDO_MC_Fen_Sel < <(xdotool "${_XDO_MC_Comm_search[@]}")
else
    readarray -t _XDO_MC_Fen_Sel < <(xdotool "${_XDO_MC_Comm_deb[@]}")
fi


### Séparation CMD_XDO2 si présence 'exec' + Contrôle du format de la commande 'exec' + Affectation des ID fenêtres.
for _XDO_MC_i in "${!_XDO_MC_Comm_fin[@]}"
do
    # Affectation ID fenêtre par numéro dans la pile.
    if [[ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" =~ ^%[[:digit:]]*$ ]]
    then
        _XDO_MC_Comm_fin[$_XDO_MC_i]="${_XDO_MC_Fen_Sel[$((${_XDO_MC_Comm_fin[$_XDO_MC_i]:1}-1))]}"
    # Affectation dynamique ID fenêtre cliquée (marqueur §).
    elif [ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" = "$" ]
    then
        _XDO_MC_Comm_fin[$_XDO_MC_i]="§0"
    # Affectation des ID fenêtres de toute la pile.
    elif [ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" = "@" ]
    then
        _XDO_MC_cmd="${_XDO_MC_Comm_fin[$((i-1))]}"
        unset '_XDO_MC_Comm_fin[$((i-1))]' '_XDO_MC_Comm_fin[$i]'
        for _XDO_MC_fen in "${_XDO_MC_Fen_Sel[@]}"
        do
            _XDO_MC_Comm_fin=( "${_XDO_MC_Comm_fin[@]:0:$((_XDO_MC_i-1))}" "$_XDO_MC_cmd" "$_XDO_MC_fen" "${_XDO_MC_Comm_fin[@]:$((_XDO_MC_i-1))}" )
            i=$((i+2))
        done
    # Début commande 'exec'.
    elif [ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" = "exec" ]
    then
        # Contrôle du format commande 'exec'
        test_form_exec "${_XDO_MC_Comm_fin[@]:$_XDO_MC_i}" || err_form_exec

        # Séparation Comm_fin1
        if [ $((_XDO_MC_i)) -gt 0 ]
        then
            _XDO_MC_Comm_fin1=( "${_XDO_MC_Comm_fin[@]:0:$((_XDO_MC_i))}" )
        fi
        _XDO_MC_i=$((_XDO_MC_i+1))

        # Séparation commande exec
        until [[ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" = ";" ]]
        do
            _XDO_MC_exec[$_XDO_MC_i]="${_XDO_MC_Comm_fin[$_XDO_MC_i]}"
            _XDO_MC_i=$((_XDO_MC_i+1))
        done
        _XDO_MC_j="$_XDO_MC_i"
    fi
done
# Séparation Comm_fin2.
if [ "${_XDO_MC_exec[*]}" ]
then
    _XDO_MC_Comm_fin2=( "${_XDO_MC_Comm_fin[@]:$((_XDO_MC_j+1))}" )
    unset _XDO_MC_Comm_fin
fi


### Activation de l'affectation dynamique ID fenêtre cliquée.
if [[ ${_XDO_MC_Comm_fin[*]} =~ " §0 "|" §0"$ ]]
then
    _XDO_MC_trait="ON"
else
    if [[ ${_XDO_MC_Comm_fin1[*]} =~ " §0 "|" §0"$ ]]
    then
        _XDO_MC_trait1="ON"
    fi
    if [[ ${_XDO_MC_Comm_fin2[*]} =~ " §0 "|" §0"$ ]]
    then
        _XDO_MC_trait2="ON"
    fi
fi


### Raison de recherche du clic souris (toutes ou une fenêtre de la pile).
if [ "$_XDO_MC_rais" = "@" ]
then
    _XDO_MC_id_window="${_XDO_MC_Fen_Sel[*]}"
else
    _XDO_MC_id_window="${_XDO_MC_Fen_Sel[$((--_XDO_MC_rais))]}"
fi


### Events à écouter (option -e), par défaut : toutes les souris + celles branchées à chaud.
    # Mise en place d'une pile d'enregistrement des event
_XDO_MC_fifo="/tmp/${0##*/}_$$_fifo"
mkfifo "$_XDO_MC_fifo"
    # Ouverture en Lecture/Écriture de la pile
exec 6<>"$_XDO_MC_fifo" 4>"$_XDO_MC_fifo" 5<"$_XDO_MC_fifo" 6>&-  # fd 6 fermé, reste fd 4 et fd 5.
    # Nettoyage si sortie quelconque. Appel de la fontion exit_trap (voir plus haut).
trap 'exit_trap "$_XDO_MC_fifo"' TERM HUP INT ABRT QUIT EXIT >/dev/null 2>&1

    # Enregistrement des event souris dans la file selon l'option '-e'.
if [ "$_XDO_MC_opt_e" ]
then
    readarray -td, _XDO_MC_event <<< "$_XDO_MC_opt_e"
    readarray -t _XDO_MC_event <<<"${_XDO_MC_event[@]/#/\/dev\/input\/event}"
    listen_event "${_XDO_MC_event[@]}"
else
    readarray -t _XDO_MC_event < <(realpath /dev/input/by-path/*event-mouse)
    listen_event "${_XDO_MC_event[@]}"
fi >&4

    # Ajout des nouveaux events souris trouvés (branchement à chaud) selon options '-f' et '-i'.
if [ "$_XDO_MC_opt_f" ] || [ ! "$_XDO_MC_opt_i" ]
then
    while read -r
    do
        if [[ $REPLY =~ event-mouse$ ]]
        then
            evtest "$(realpath "$REPLY")" &
        fi
    done < <(inotifywait -qme create --format %w%f /dev/input/by-path) &
fi >&4
###---


### Affichage Commande Recherche (option -p et/ou commande xdotool)
if [ "$_XDO_MC_opt_p" ]
then
    printf "%s\n" "${_XDO_MC_Fen_Sel[@]}"
fi
if [ "${_XDO_MC_Comm_search[*]}" ]
then
    xdotool "${_XDO_MC_Comm_deb[@]}"
fi


### Test en continu du clic souris et exécution de la commande après clic.
shopt -s extglob    # Pour la subsitution dans l'ajout de l'ID fenêtre cliquée.
while read -r <&5
do
    if [ "$REPLY" = "EOF" ]   # Possibilité d'écrire "EOF" dans la file pour arrêter le script :
    then                      #     echo "EOF" > /tmp/Nom_PID_fifo    avec nom=nom_de_ce_script et PID=pid_de_ce_script
        _XDO_MC_retour=99     # Descripteur fd/4 accessible aux processus enfants :
        break                 #     echo "EOF" >&4
    fi
    # Détection du clic souris
    if [[ $REPLY =~ $_XDO_MC_regex ]]
    then
        _XDO_MC_wc=$(xdotool getmouselocation | awk -F: '{printf $NF}')
        export XDOclic="${BASH_REMATCH[0]:4:1}${BASH_REMATCH[0]:$((${#BASH_REMATCH[0]}-1)):1}"
        ### Évite le clic menu contextuel
        if [ "$_XDO_MC_wc" = "0" ]
        then
            continue
        fi
        # Match l'ID de la fenêtre cliquée
        if [[ $_XDO_MC_id_window =~ " $_XDO_MC_wc "|^"$_XDO_MC_wc "|" $_XDO_MC_wc"$|^$_XDO_MC_wc$ ]]
        then
            # Ajout de l'ID fenêtre cliquée dans les commandes le demandant (marqueur §).
            if [ "$_XDO_MC_trait" ]
            then
                _XDO_MC_Comm_fin=( "${_XDO_MC_Comm_fin[@]//§[[:digit:]]*/§$_XDO_MC_wc}" )
            else
                if [ "$_XDO_MC_trait1" ]
                then
                    _XDO_MC_Comm_fin1=( "${_XDO_MC_Comm_fin1[@]//§[[:digit:]]*/§$_XDO_MC_wc}" )
                fi
                if [ "$_XDO_MC_trait2" ]
                then
                    _XDO_MC_Comm_fin2=( "${_XDO_MC_Comm_fin2[@]//§[[:digit:]]*/§$_XDO_MC_wc}" )
                fi
            fi

            # Exécution de la commande après clic.
            if [ "${_XDO_MC_exec[*]}" ]
            then
                if [ "${_XDO_MC_Comm_fin1[*]}" ]
                then
                    xdotool "${_XDO_MC_Comm_fin1[@]#§}"
                fi
                xdotool exec "${_XDO_MC_exec[@]}"
                _XDO_MC_retour=$?
                if [ "$_XDO_MC_retour" -gt 0 ]
                then
                    if [ "$_XDO_MC_opt_q" ]
                    then
                        break
                    fi
                    continue
                fi
                if [ "${_XDO_MC_Comm_fin2[*]}" ]
                then
                    xdotool "${_XDO_MC_Comm_fin2[@]#§}"
                    _XDO_MC_retour=$?
                fi
            else
                xdotool "${_XDO_MC_Comm_fin[@]#§}"
                _XDO_MC_retour=$?
            fi

            # One-shot or not ?
            if [ "$_XDO_MC_opt_q" ]
            then
                break
            fi
        fi
    fi
done

exit $_XDO_MC_retour


Edit: Pour copier un si grand script, sélectionner la première ligne (le shebang), descendre tout en bas du script avec l'ascenseur, placer la souris derrière le dernier caractère de la dernière ligne, maintenir enfoncé la touche SHIFT et cliquer (bouton gauche) : tout est sélectionné wink

Retour d'un exemple (compliqué tongue) :

xdo2 -p search --name "conky" getwindowname %@ +@ exec --sync bash -c 'echo -n "Le $(date), $USER a cliqué sur "' \; getwindowname $


54525953
50331650
31457282
conky_images
conky_titre
conky_total
Le dim. 13 févr. 2022 09:07:59 CET, tawal a cliqué sur conky_total
Le dim. 13 févr. 2022 09:08:00 CET, tawal a cliqué sur conky_titre
^C


Bon, on comprend sur quoi j'ai cliqué smile
Décomposition de la commande :
   -p : Option affichant la pile WINDOW STACK (les 3 premières lignes du retour = id des fenêtres trouvées).
   search --name "conky" getwindowname %@ : CMD_XDOTOOL avec affichage des noms de fenêtres trouvées.
   +@ : Recherche de clic sur toute la pile WINDOW STACK
   exec --sync bash -c 'echo -n "Le $(date), $USER a cliqué sur "' \; getwindowname $ : CMD_XDO2 commande à exécuter si clic réussi.
         la commande exec se termine par \;.
         le $ du dernier getwindowname se réfère à l'id de la fenêtre cliquée.

Edit:
Mise à jour importante.
Corrections des bugs, mise au point, ajout d'options.

Edit2:
Mise à jour du script.
Prise en charge des souris branchées à chaud (si l'option -e n'est pas utilisée évidemment)
Ajout du test de présence des programmes requis (xdotool, evtest et inotifywait)

Edit3:
Mise à jour finale du script.
Ré-écriture et restructuration du script.
Mise au propre des fonctions (ne touchent plus directement aux variables globales).
Ajout d'options (-f et -i)
Mise à jour de l'aide.

Dernière modification par Tawal (01-03-2022 16:07:04)


Comme la science n'est pas infuse, elle se diffuse.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#2 15-01-2022 11:20:07

Tawal
Membre
Distrib. : Debian Stable à jour
Noyau : amd64
(G)UI : Xfce
Inscription : 25-02-2021

Re : Alternative à xdotool mouse-click

Up,

Désolé pour hier soir, avec ce message plus que tronqué zen.gif
Mais j'ai fait d'abord une mauvaise manipulation entre "Prévisualisation" et "Valider".
Puis, est survenu une coupure de courant, en pleine édition de mon message !
Le voilà donc à jour.

Comme la science n'est pas infuse, elle se diffuse.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#3 13-02-2022 10:30:16

Tawal
Membre
Distrib. : Debian Stable à jour
Noyau : amd64
(G)UI : Xfce
Inscription : 25-02-2021

Re : Alternative à xdotool mouse-click

up : mise à jour du script.

Edit:
Ajout au #1 de la description de la commande d'exemple.

Dernière modification par Tawal (13-02-2022 11:09:09)


Comme la science n'est pas infuse, elle se diffuse.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#4 20-02-2022 20:24:27

Tawal
Membre
Distrib. : Debian Stable à jour
Noyau : amd64
(G)UI : Xfce
Inscription : 25-02-2021

Re : Alternative à xdotool mouse-click

up, mise à jour du script ... et dernière vu l'intérêt.

Voir Edit3 du #1.

Bref, au moins, il existe un contournement du bug par un script bash tongue

@+

Edit:
L'avantage de mon script :

$ xdotool search --name "conky" behave %@ mouse-enter exec echo "OK" getwindowname %1
OK getwindowname %1
OK getwindowname %1
^C
$ xdotool search --name "conky" behave %@ mouse-enter exec /bin/true getwindowname %1
^C
$ xdotool search --name "conky" behave %@ mouse-enter exec --sync /bin/true getwindowname %1
^C
$ # Les ^C sans retour car pas de réponse bien que la souris soit entrée dans un conky !
$
$ xdo2 search --name "conky" +@ exec echo "Ok" \; getwindowname $
Ok
conky_total
Ok
conky_titre
^C$
$


Bon déjà, on peut aligner des commandes xdotool après la commande exec.
Mais en plus, ça remet correctement la saveur de 'exec --sync' :

$ xdo2 search --name "conky" +@ exec /bin/false \; getwindowname $
conky_total
conky_titre
^C$
$ xdo2 search --name "conky" +@ exec --sync /bin/false \; getwindowname $
^C$
$ # Pas de retour malgré les clics.
$



Edit2:
Du coup, ça aussi c'est intéressant :

$ xdo2 -q search --name "conky" +@ exec /bin/false \; getwindowname $
conky_titre
$ echo $?
0
$
$ xdo2 -q search --name "conky" +@ exec --sync /bin/false \; getwindowname $
$ echo $?
1
$

Dernière modification par Tawal (21-02-2022 01:36:55)


Comme la science n'est pas infuse, elle se diffuse.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#5 23-02-2022 18:47:18

Tawal
Membre
Distrib. : Debian Stable à jour
Noyau : amd64
(G)UI : Xfce
Inscription : 25-02-2021

Re : Alternative à xdotool mouse-click

Re,

En fait, c'est une usine à gaz !
Je propose une version plus "légère", sans options (à part l'aide) et plus simple à utiliser, appelé lxdo2 (l pour léger tongue)
Toujours l'argument +N pour remplacer le behave %N mouse-click.
La seule particularité est qu'il faut, dans la 2ième partie de la commande, ajouter "%1" à toute commande xdotool le réclamant.
Bref, voici son aide :

lxdo2 --help


Usage :    lxdo2   CMD_XDOTOOL
           lxdo2   CMD_XDOTOOL_1   +N   CMD_XDOTOOL_2
           lxdo2   -h

Surcouche de 'xdotool'.
Palie au bug de 'xdotool ... behave . mouse-click ...'.
  +N remplace le 'behave %N mouse-click'
  N doit être un nombre ou @.
  CMD_XDOTOOL_1 et CMD_XDOTOOL_2 sont des lignes de commande xdotool avec
  la particularité pour CMD_XDOTOOL_2 où il faut indiquer %1 comme argument à
  toute commande xdotool réclamant un ID de fenêtre.
  (option de commande comprise)

Options :
    -h, --help      Afficher cette aide et quitter.

Exemple :
   $ lxdo2 search --name ".*" +@ getwindowname %1 exec date +%s
   Bureau
   1645371391
   ^C$

Nécessités : xdotool, evtest, inotify-tools


Le script :

#!/bin/bash


### Pré-requis :
#
#   Nécessite : xdotool (sudo apt install xdotool)
#               evtest  (sudo apt install evtest)
#               inotifywait (sudo apt install inotify-tools)
#
#   Puis 2 méthodes au choix :
#       1: Inscrire la commande /usr/bin/evtest dans /etc/sudoers de cette façon : sudo visudo
#              nom_user  ALL = NOPASSWD: /usr/bin/evtest
#          Modifier le script à la ligne 227 pour ajouter 'sudo' devant 'evtest'
#
#       2: Méthode utilsée dans le script :
#          Créer un groupe 'mouse-event' : sudo addgroup mouse-event
#          Créer une règle udev : /etc/udev/rules.d/99-MesMouses.rules contenant :
#              SUBSYSTEM=="input", SYMLINK=="input/by-path/*event-mouse", GROUP="mouse_event", MODE="0660"
#          Ajouter les utilisateurs pouvant utiliser ce script au groupe 'mouse_event' : sudo addgroup user mouse_event
#          Actif dès le prochain boot.
#          Pour une utilisation immédiate (déconnexion session) : sudo udevadm trigger
### ---


### Protection contre la collision de variables (pas d'accès à l'aide)
readarray -t _XDO_MC_col < <(set | grep "^_XDO_MC_.*=.*$")
if [ "${_XDO_MC_col[*]}" ]
then
    echo "${0##*/}: Export de variables interdites"
    printf "\t%s\n" "${_XDO_MC_col[@]}"
    echo "Vérifiez votre environnement !"
    exit 127
fi >&2


### Vérification de la présence des programmes requis
if [ "$1" != "-h" ] && [ "$1" != "--help" ]
then
    for _XDO_MC_i in xdotool evtest inotifywait
    do
        if ! hash "$_XDO_MC_i" 2>/dev/null
        then
            if [ "$1" = inotifywait ]
            then
                _XDO_MC_j="inotify-tools"
            else
                _XDO_MC_j="$_XDO_MC_i"
            fi
            echo "${0##*/}: Nécessite $_XDO_MC_i (sudo apt install $_XDO_MC_j)."
            _XDO_MC_quit="ON"
        fi
    done
    [ "$_XDO_MC_quit" ] && exit 1
fi >&2


### Fonctions
usage ()
{
    echo -e "Usage :    \E[1m${0##*/}   CMD_XDOTOOL"
    echo -e "           \E[1m${0##*/}   CMD_XDOTOOL_1   +N   CMD_XDOTOOL_2\E[0m"
    echo -e "           \E[1m${0##*/}   -h\E[0m"
    echo
    echo -e "Surcouche de '\E[1mxdotool\E[0m'."
    echo -e "Palie au bug de '\E[3mxdotool ... behave . mouse-click ...\E[0m'."
    echo -e "  \E[1m+N\E[0m remplace le '\E[3mbehave %N mouse-click\E[0m'"
    echo -e "  \E[1mN\E[0m doit être un nombre ou \E[1m@\E[0m."
    echo -e "  \E[1mCMD_XDOTOOL_1\E[0m et \E[1mCMD_XDOTOOL_2\E[0m sont des lignes de commande \E[1mxdotool\E[0m avec"
    echo -e "  la particularité pour \E[1mCMD_XDOTOOL_2\E[0m où il faut indiquer \E[1m%1\E[0m comme argument à"
    echo -e "  toute commande \E[1mxdotool\E[0m réclamant un ID de fenêtre."
    echo    "  (option de commande comprise)"
    echo
    echo    "Options :"
    echo    "    -h, --help      Afficher cette aide et quitter."
    echo
    echo    "Exemple :"
    echo    "   $ ${0##*/} search --name \".*\" +@ getwindowname %1 exec bash -c 'date'"
    echo    "   Bureau"
    echo    "   1645371391"
    echo    "   ^C$"
    echo
    echo    "Nécessités : xdotool, evtest, inotify-tools"
    exit 0
}

err_opt ()
{   # Utilisation d'option non reconnue et sortie.
    echo "${0##*/}: Option non-reconnue : $1"
    exit 1
} >&2

pids_child ()
{   # Liste les processus enfants du script.
    local i T
    readarray -t T < <(ps --no-headers --ppid "$1" -o pid)
    (("${#T[*]}")) && {
        for i in "${T[@]}"
        do
            pids_child $i   # $i not quoted to avoid head blank.
        done
        echo "${T[@]}"
    }
}

exit_trap ()
{   # Action à mener par la capture des signaux TERM HUP INT ABRT QUIT EXIT
    kill -15 $(pids_child $$) >/dev/null 2>&1
    exec 4>&-
    exec 5>&-
    rm -f "$1"
}
###--- (Fin Fonctions)


### Gestion des options :
while getopts :h-: _XDO_MC_opt
do
    case $_XDO_MC_opt in
        h) usage
           ;;

        -) case $OPTARG in
               help) usage
                     ;;

                  *) err_opt --${!OPTIND}
                     ;;
           esac
           ;;

        *)  err_opt -"$OPTARG"
            ;;
    esac
done
shift $((--OPTIND))


### Séparation CMD_XDOTOOL_1 et CMD_XDOTOOL_2 et Séparation de Comm_search en cas d'affichage demandé dans CMD_XDOTOOL_1.
_XDO_MC_Comm=( "$@" )
for _XDO_MC_i in "${!_XDO_MC_Comm[@]}"
do
    if [ "${_XDO_MC_Comm[$_XDO_MC_i]:0:1}" != "+" ]
    then
        if [ "${_XDO_MC_Comm[$_XDO_MC_i]:0:3}" = "get" ] && \
           [[ ! ${_XDO_MC_Comm[$_XDO_MC_i]} =~ ^getactivewindow$|^getwindowfocus$ ]] && \
           [ ! "${_XDO_MC_Comm_search[*]}" ]
        then
            _XDO_MC_Comm_search=( "${_XDO_MC_Comm[@]:0:$_XDO_MC_i}" )
        fi
        _XDO_MC_Comm_deb[$_XDO_MC_i]="${_XDO_MC_Comm[$_XDO_MC_i]}"
        continue
    else
        _XDO_MC_rais="${_XDO_MC_Comm[$_XDO_MC_i]#+}"
    fi
    shift $((_XDO_MC_i+1))
    break
done


### Commande sans 'mouse-click' (pas d'argument +N ou +@ dans la ligne de commande).
if [ ! "$_XDO_MC_rais" ]
then
    xdotool "${_XDO_MC_Comm[@]}"
    exit
fi
unset _XDO_MC_Comm


### Commande après clic
_XDO_MC_Comm_fin=( "$@" )


### Tableau des fenêtres trouvées.
if [ "${_XDO_MC_Comm_search[*]}" ]
then
    readarray -t _XDO_MC_Fen_Sel < <(xdotool "${_XDO_MC_Comm_search[@]}")
else
    readarray -t _XDO_MC_Fen_Sel < <(xdotool "${_XDO_MC_Comm_deb[@]}")
fi


### Raison de recherche du clic souris (toutes ou une fenêtre de la pile).
if [ "$_XDO_MC_rais" = "@" ]
then
    _XDO_MC_id_window="${_XDO_MC_Fen_Sel[*]}"
else
    _XDO_MC_id_window="${_XDO_MC_Fen_Sel[$((--_XDO_MC_rais))]}"
fi


### Affectation des ID fenêtres.
for _XDO_MC_i in "${!_XDO_MC_Comm_fin[@]}"
do
    if [ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" = "%1" ]
    then
        if [ "$_XDO_MC_rais" = "@" ]
        then
            # Affectation dynamique ID fenêtre cliquée (marqueur §).
            _XDO_MC_Comm_fin[$_XDO_MC_i]="§0"
            _XDO_MC_trait="ON"
        else
            # Affectation ID fenêtre cliquable par numéro dans la pile.
            _XDO_MC_Comm_fin[$_XDO_MC_i]="$_XDO_MC_id_window"
        fi
    elif [ "${_XDO_MC_Comm_fin[$_XDO_MC_i]}" = "exec" ]
    then
        break   # Le "Command Chaining" ne fonctionne pas après 'exec'.
    fi
done


### Events à écouter : toutes les souris présentes (pas de branchement à chaud).

    # Mise en place d'une pile d'enregistrement des event
_XDO_MC_fifo="/tmp/${0##*/}_$$_fifo"
mkfifo "$_XDO_MC_fifo"

    # Ouverture en Lecture/Écriture de la pile
exec 6<>"$_XDO_MC_fifo" 4>"$_XDO_MC_fifo" 5<"$_XDO_MC_fifo" 6>&-  # fd 6 fermé, reste fd 4 et fd 5.

    # Nettoyage si sortie quelconque. Appel de la fontion f_trap (voir plus haut).
trap 'exit_trap "$_XDO_MC_fifo"' TERM HUP INT ABRT QUIT EXIT >/dev/null 2>&1

    # Enregistrement des event souris dans la file.
for _XDO_MC_i in /dev/input/by-path/*event-mouse
do
    evtest "$(realpath "$_XDO_MC_i")" &
done >&4
###---


### Affichage Commande Recherche (si il y a).
if [ "${_XDO_MC_Comm_search[*]}" ]
then
    xdotool "${_XDO_MC_Comm_deb[@]}"
fi


### Test en continu du clic souris et exécution de la commande après clic.
shopt -s extglob    # Pour la subsitution dans l'ajout de l'ID fenêtre cliquée.
while read -r <&5
do
    # Détection du clic souris
    if [[ $REPLY =~ BTN_LEFT.*value\ 1$ ]]
    then
        _XDO_MC_wc=$(xdotool getmouselocation | awk -F: '{printf $NF}')
        ### Évite le clic menu contextuel
        if [ "$_XDO_MC_wc" = "0" ]
        then
            continue
        fi
        # Match l'ID de la fenêtre cliquée
        if [[ $_XDO_MC_id_window =~ " $_XDO_MC_wc "|^"$_XDO_MC_wc "|" $_XDO_MC_wc"$|^$_XDO_MC_wc$ ]]
        then
            # Ajout de l'ID fenêtre cliquée dans les commandes le demandant (marqueur §).
            if [ "$_XDO_MC_trait" ]
            then
                _XDO_MC_Comm_fin=( "${_XDO_MC_Comm_fin[@]//§[[:digit:]]*/§$_XDO_MC_wc}" )
            fi

            # Exécution de la commande après clic.
            xdotool "${_XDO_MC_Comm_fin[@]#§}"
        fi
    fi
done

exit


Et puis un exemple concret :

lxdo2 search --name conky getwindowname %@    +@    getwindowname %1 exec date


conky_images
conky_total
conky_titre
conky_total
mer. 23 févr. 2022 17:46:09 CET
conky_total
mer. 23 févr. 2022 17:46:16 CET
^C

Dernière modification par Tawal (01-03-2022 14:08:42)


Comme la science n'est pas infuse, elle se diffuse.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

Pied de page des forums