web-dev-qa-db-fra.com

Simulation de tremblement (par exemple, maladie de Parkinson) avec la souris sur une page Web?

Je travaille pour une fondation qui sensibilise Internet à l'accessibilité. Pour une présentation, nous souhaitons offrir un petit atelier simulant différentes incapacités/déficiences pour les personnes. Cela se fait via un site web créé spécialement pour cette présentation.

L'une des déficiences démontrées est le tremblement, ce qui signifie que les mouvements de la main sont tremblants et difficiles à contrôler. Avec cette déficience, il est très difficile de déplacer le curseur de la souris avec précision et d’appuyer sur le bouton de la souris lorsque la souris survole un lien. À la fois des personnes âgées et des personnes atteintes d’une maladie, par exemple: Parkinson, peut souffrir de tremblement.

J'aimerais maintenant déplacer le curseur de la souris d'une manière imprévisible, de sorte qu'il est très difficile pour les personnes de cliquer sur un petit bouton. Comme JavaScript ne permet pas de déplacer directement le curseur de la souris, je cherche d’autres moyens d’y parvenir. Je suis venu avec les idées suivantes:

  • Utilisation d’un pilote/utilitaire de souris simulant le tremblement de la souris.
  • Cachez le curseur de la souris via CSS, placez une animation GIF d'un curseur de souris tremblant à la place du curseur d'origine (avec JavaScript), puis ne cliquez sur le lien cible que toutes les quelques secondes environ. Cela donnerait au moins l'impression que l'on clique toujours au mauvais moment.

Alors que la première idée serait plutôt cool, je ne pouvais pas trouver un outil comme celui-ci, que ce soit pour Mac ou pour Windows. Et je n'ai aucune compétence pour programmer une telle chose moi-même.

La deuxième idée semble un peu maladroite, mais elle produirait l’effet souhaité, je pense.

Quelqu'un a-t-il une autre idée?

204
Joshua Muheim

J'ai fait une démonstration rapide de quelque chose sur lequel vous devriez pouvoir fonder votre code, en utilisant le API Pointer Lock .

J'ai forké ce repo pointer-lock-demo et l'ai modifié pour ajouter un élément de mouvement aléatoire.

Voici le lien vers ma page GitHub: https://aristocrates.github.io/pointer-lock-demo
Et voici le lien vers mon dépôt: https://github.com/aristocrates/pointer-lock-demo

Le code javascript d'importance est contenu dans app.js, Dans la méthode canvasLoop(e).

La seule chose que j'ai modifiée par rapport à la démo originale est après les lignes

x += movementX * 2;
y += movementY * 2;

J'ai ajouté deux lignes pour représenter un mouvement aléatoire:

x += Math.floor(Math.random()*3 - 1);
y += Math.floor(Math.random()*3 - 1);

Il y a encore beaucoup de choses que vous pourriez améliorer, mais j'espère que cela peut vous aider à démarrer.

148
Aristocrates

Manière non-javascript

En fait, j'aime bien les solutions, qui peuvent être basées sur le javascript, car elles sont plus susceptibles d'être liées au Web et de bonnes chances - indépendantes du système d'exploitation. Cependant, je réfléchissais à la façon de résoudre votre problème pour tous les navigateurs, car les solutions javascript, dans ce cas, seront difficiles à ajuster pour tous les navigateurs possibles (je ne suis pas sûr que ce soit possible du tout).

Ainsi, comme vous l’avez mentionné, il existe un autre moyen - c’est-à-dire d’imiter le comportement au niveau du système d’exploitation. Cela a aussi un autre avantage - vous pouvez être sûr que pour le navigateur, il a l’air 100% comme c’était un humain (parce que, c’est le pilote qui envoie le signal). Vous pouvez donc utiliser des solutions basées sur les pilotes/périphériques avec n’importe quel navigateur (ou même dans certaines situations, lorsque javascript est désactivé).

Linux

Malheureusement, l'implication du pilote/périphérique entraîne immédiatement une dépendance du système d'exploitation. Donc, pour chaque OS, vous aurez besoin de votre propre solution. Dans cet article, je me suis concentré sur une solution basée sur Linux (donc fonctionnera sous Linux) - et un peu sur Mac OS. Avec Linux, il est possible d'écrire des événements sur un périphérique de manière explicite. Voici donc un exemple de fonction avec boucle principale:

int main()
{
    struct input_event event, event_end;

    int  fd = open("/dev/input/event4", O_RDWR);
    long ma = getInteger("Enter max amplitude [points, 0..50]: ", 0, 50);
    long ta = getInteger("Enter max wait time [usecs , 0..200000]: ", 0, 200000);
    if (fd < 0)
    {
        printf("Mouse access attempt failed:%s\n", strerror(errno));
        return -1;
    }
    memset(&event, 0, sizeof(event));
    memset(&event, 0, sizeof(event_end));
    gettimeofday(&event.time, NULL);
    event.type = EV_REL;
    gettimeofday(&event_end.time, NULL);
    event_end.type = EV_SYN;
    event_end.code = SYN_REPORT;
    event_end.value = 0;
    while(1)
    {
        event.code  = Rand() % 2 ? REL_X : REL_Y;
        event.value = (Rand() % 2 ? -1 : 1) * randomTill(ma);
        write(fd, &event, sizeof(event));
        write(fd, &event_end, sizeof(event_end));
        usleep(randomTill(ta));
    }
    close(fd);
    return 0;
}

Mon code complet pour le problème soit trouvé ici . Le programme demandera l'amplitude du "tremblement" et sa fréquence (ainsi, combien de fois en micro-secondes séparent les "tremblements"). Pour émuler la situation, il forcera la souris à se déplacer de manière aléatoire pour que 0..X Pointe dans une direction aléatoire (haut-bas-gauche-en bas à gauche) et attende au hasard 0..Y Quelques micro-secondes jusqu'au prochain "tremblement", puis X est l'amplitude de "tremblement" et Y est la fréquence de "tremblement"

Une autre chose peut être d’adapter le programme à votre système. Le programme est "factice" et ne peut pas détecter la souris lui-même, donc "/dev/input/event4" Est codé en dur. Pour réaliser ce qui peut être un identifiant pour votre système, vous pouvez essayer:

user@Host:/path$ cat /proc/bus/input/devices | grep mouse
H: Handlers=mouse0 event3 
H: Handlers=mouse1 event4

Et les possibilités sont donc "event3" Et "event4" - mais pour votre système, elles peuvent avoir d'autres valeurs. Donc, si cela diffère du code C actuellement utilisé, changez simplement la ligne correspondante (donc, ligne avec int fd = open("/dev/input/event4", O_RDWR); et placez votre périphérique à la place de event4)

Une démo gif pour ce programme (fréquence d'image faible, malheureusement, alors gardez une image pas trop grande) ici .

Petite remarque (si vous ne savez pas quoi faire avec le code C) - pour compiler le programme ci-dessus, utilisez simplement:

user@Host:/path$ gcc -std=gnu99 file.c -o m

file.c est le nom de votre fichier de code source C, vous obtiendrez un exécutable, appelé m dans votre répertoire. Très probablement, vous aurez besoin d'autorisations pour écrire directement dans le périphérique de la souris. Vous pouvez donc utiliser Sudo:

user@Host:/path$ Sudo ./m

Autre OS

La logique restera la même:

  • Trouver un moyen d'accéder à votre souris
  • Écrire l'événement de la souris en mouvement
  • Appliquez la randomisation à votre événement

C'est ça. Par exemple, Mac OS a sa propre façon de travailler avec la souris (contrairement à Linux, Mac n’a pas procfs), c’est bien décrit ici .

Comme conclusion

Ce qui est mieux - des solutions javascript ou orientées vers les appareils - revient à vous, car certaines conditions (telles que l'utilisation simultanée de plusieurs navigateurs ou d'un système d'exploitation) peuvent tout décider dans ce cas. Par conséquent, j’ai fourni des directives avec certains exemples concrets sur la manière de les mettre en œuvre au niveau du système d’exploitation. L'avantage ici est que cette solution est multi-navigateur, mais en tant que coût, nous avons un programme lié au système d'exploitation.

36
Alma Do

Je l'ai fait comme une blague une fois, sur le Puppy Linux Forum et j'ai obtenu le commentaire suivant:

Les personnes atteintes de la maladie de Parkinson ne penseront pas que c'est drôle !!!

Cure ici est simplement cntrl-C, heureusement.

Voici le script Shell qui nécessite xdotool

#!/bin/sh
while :; do
   xdotool mousemove_relative -- -$(($RANDOM % 10)) $(($RANDOM % 10))
   xdotool mousemove_relative -- $(($RANDOM % 10)) -$(($RANDOM % 10))
   sleep ${1:-.1} #adjust this as necessary for effect
done

Nommez parkinson_sim et lancez un argument optionnel indiquant le délai entre les secousses pouvant aller de 0,001 à 999,0.

parkinson_sim [time_between_tremors_in_seconds] #default est 0.1

J'ai fait l'erreur de cliquer dessus moi-même au lieu de l'exécuter à partir de la ligne de commande et j'ai rapidement découvert à quel point cela devait être frustrant. Il m'a fallu plusieurs essais pour ouvrir une fenêtre de terminal afin de la tuer.

23
technosaurus

Votre deuxième idée (masquer le curseur) est à mi-chemin de celle qui, à mon avis, peut vous convenir:

  • Masquer le curseur de la souris via CSS, comme vous le suggérez. (cursor:none IIRC)
  • Au lieu d’un curseur GIF à curseur tremblotant, utilisez un positionnement absolu image + CSS + JS pour émuler le pointeur de la souris; c'est-à-dire, suivez la souris autour de la page et plantez l'image du curseur à l'emplacement où se trouverait le curseur de la souris.

Ensuite, vous ajoutez des maths de tremblement au code de votre curseur pour "secouer" le curseur. À vous de déterminer quelles sont les bonnes courbes pour simuler correctement l’entrée des tremblements.

Enfin: pour tous les contrôles que vous programmez (liens, etc.):

  • capturez les événements liés aux clics, déplacez-les vers l'emplacement "tremblement" actuel en fonction de l'état de vos courbes de tremblement, et vérifiez vos éléments pour voir si l'utilisateur a éjecté l'élément ou ne l'a pas fait, ou éventuellement dans un élément qui ne l'était pas .

Un bonus majeur avec cette implémentation: votre 'curseur tremblant' sera affiché sur les appareils tactiles, qui n'auront pas de curseur pour commencer.


Modifier:

D'après la base JSFiddle de Michael Theriot (très propre et utile!) Tirée des commentaires, en voici une qui bouge constamment avec un balayage distribué normalement autour de l'emplacement actuel du curseur: http://jsfiddle.net/benmosher/0x4mc64v/ 4 /

(Le tableau normal est le résultat de l'appel de rnorm(100) dans ma console R. La manière la plus simple que je puisse imaginer dans JS d'échantillonner un entier aléatoire distribué normalement.)

16
Ben Mosher

Juste une idée pour que le tremblement soit "correct", vous pouvez enregistrer le mouvement de la souris d'un vrai patient, cela le rend plus authentique lorsque vous dites aux gens d'où proviennent les données.

Là, un script permettant à un chat de suivre le curseur de votre souris, vous pouvez en ajuster un pour laisser un second curseur suivre votre curseur. La page calcule la position du second curseur afin de déterminer si un événement de clic a réussi ou non.

Si vous le pouvez, rendez-vous sur Internet, vous atteindrez ainsi beaucoup plus de personnes que de leur demander d'installer un programme, d'activer le flash ou quoi que ce soit d'autre.

14
user3934260

Au lieu d'essayer de déplacer le pointeur, vous pouvez déplacer l'application (page Web) à la place. J'ai écrit un formulaire HTML simple qui contient des champs de saisie. Lorsque vous déplacez la souris sur le formulaire, le formulaire se déplace.

Vous pouvez voir ne démo de la forme en mouvement sur jsfiddle . Essayez de cliquer sur l'un des champs de saisie pour voir l'effet.

J'ai utilisé l'effet jquery shake pour y parvenir. Le javascript de l'effet shake ressemble à ceci et ne fait que déplacer le formulaire de haut en bas chaque fois que la souris est déplacée dessus:

<script type="text/javascript">
    $(document).ready(function() {
        $("#toggle").hover(function () {
            $(this).effect("shake", { direction: "up", times: 1, distance: 40}, 1000);
        });
    });
</script>

Bien que la forme ne fasse que monter et descendre, je pense que cela a l'effet désiré. Vous pouvez jouer avec les paramètres (direction, temps, distance, ainsi que le "1000" non nommé ci-dessus) pour ajuster le mouvement de la forme.

10
chue x

Pourquoi ne pas utiliser une solution matérielle? Il y a certaines souris sur lesquelles vous pouvez peser, comme la Logitech G500. Au lieu de mettre un poids, installez un petit moteur oscillant qui fait trembler légèrement la souris. Cela simulait également davantage le désordre réel: ce n’est pas seulement le curseur qui tremble, mais la main entière et la souris. Et cela signifie également que vous pouvez afficher d'autres logiciels que les sites Web.

Au lieu d'une souris avec une fente de poids, vous pouvez également coller quelque chose à la souris, mais c'est plus visible.

10
Nzall

Alors que vous pensiez le faire avec un pilote de souris personnalisé, je suppose qu’un petit programme exécuté sur le PC ferait l’un ou l’autre? Si tel est le cas, voici un petit extrait de code pour C #, qui déplace le curseur de manière infinie de manière aléatoire, avec une plage de plus moins 5 pixels autour de la position actuelle du curseur. Après chaque déplacement, le programme attend entre 50 ms et 100 ms (inexact!). Le tremblement peut être configuré en adaptant les valeurs pour le déplacement et les pauses. J'ai exécuté cela dans une application console et - en fonction des valeurs - cela m'a causé beaucoup de difficulté à arrêter le programme.

Random Rand = new Random();

while(true)
{
    Cursor.Position = new Point() { X = Cursor.Position.X + Rand.Next(11)-5, Y = Cursor.Position.Y + Rand.Next(11)-5 };
    Thread.Sleep(Rand.Next(50) + 50);
}
6
Paul Kertscher

Voici une version Windows de mon script xdotool qui utilise AutoIt . C'était mon tout premier script AutoIt, et il n'a fallu que quelques minutes pour écrire, alors je suis sûr que cela peut être amélioré. Il suffit de sauvegarder avec l'extension .au3 et de l'exécuter avec AutoIt (Run Script x86).

HotKeySet("{HOME}", "GStart")
HotKeySet("{PAUSE}", "Gpause")
HotKeySet("{ESC}", "Gexit")

While 1
    Sleep(100)
WEnd

Func Gstart()
While 1
    sleep(100)
    $pos = MouseGetPos()
    $x = $pos[0] + 10 - Random(0, 20, 1)
    $y = $pos[1] + 10 - Random(0, 20, 1)
    MouseMove($x,$y)
Wend
Endfunc


Func Gpause()
While 1
   sleep(100)
Wend
Endfunc

Func Gexit()
    MsgBox(0, "exit box", "Script exited")
    Exit 0
EndFunc

Contrôles

  • Accueil: Lancer la simulation.
  • pause: pause de la simulation.
  • Esc: Quitter la simulation.

Ou utilisez ma version compilée de ici .

6
technosaurus

Vous ne pouvez pas vous attendre à ce que quelqu'un soit capable de tenir ses mains parfaitement stables, alors une chose à considérer est:

  1. Expliquez aux utilisateurs ce que vous faites et
  2. Rendez les éléments cliquables sur la page de démonstration beaucoup plus petits que la normale.
  3. Augmenter au maximum la sensibilité de la souris sur le système exemple.

Mon raisonnement est (attention, je ne suis pas un expert en ux ou en médecine) en réduisant les éléments cliquables, vous créez un problème similaire pour la plupart des personnes qu'une personne atteinte de la maladie de Parkinson rencontrerait avec un site Web quotidien.

5
jdphenix
  • Dans votre DIV, CSS-cache le curseur en utilisant cursor:none;
  • Créez une image de curseur .png et déplacez-la (left, top) avec jQ sur mousemove
  • Randomize le .png margin-left Et margin-top En utilisant un setTimeout (pour que le repositionnement se fasse en douceur, utilisez CSS3 transition ou faites-le avec jQ .animate()).

Remarque: le script ne peut pas savoir si la main est toujours sur la souris;)

function Rand(min, max) {return Math.random() * (max - min) + min;}

var $cursor = $('div img');

$('div').mousemove(function(e) {  // Make .png follow the mouse coordinates
  $cursor.css({
    left: e.pageX,
    top:e.pageY
  });
}).hover(function(e){
  $cursor.toggle(); // Show .png cursor as we enter the DIV
});

(function tremor(){ // Add tremor to .png image
  $cursor.css({
      marginLeft: Rand(-15,15), // arm tremor
      marginTop:  Rand(-30,30)  // hand contractions
  });
  setTimeout(tremor, Rand(50,100));
}());
div{
  position:absolute;
  background:#eee;
  height:100%;
  width:100%;
  cursor:none;
}

div img{
  display:none;
  position:absolute;
  transition: margin 0.2s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div><img src="http://i.stack.imgur.com/KwMGA.png"></div>
4
Roko C. Buljan

Vous pouvez utiliser un costume de simulation pour le vieil âge, tel que celui décrit dans l'article this ... rendre les mains généralement maladroites.

4
user3067860

Les parties de bas niveau de la simulation du tremblement sont bien répondues maintenant. Je vais ajouter quelque chose en se concentrant sur le type de tremblement à simuler:

La plupart des réponses implémentent un curseur de souris qui se déplace sur un chemin aléatoire avec une largeur de pas maximale fixe dans les directions X et Y.

Cela devrait fonctionner assez bien pour que vous puissiez difficilement frapper une zone spécifique comme un bouton.

Pour le problème plus général de la simulation des problèmes d’assurance-chômage causés par un tremblement provoqué par la maladie de Parkinson, il serait au moins intéressant de simuler réellement les mouvements de la main de ce type de tremblement.
Je suppose que la marche aléatoire peut ne pas être une très bonne approximation .

Il peut être difficile d’obtenir des données réelles sur les traces de la main du mouvement de tremblement bien sûr, mais il existe certainement des documents sur l’analyse de ce type de tremblement:

Le document Représentation paramétrique du mouvement des mains dans la maladie de Parkinson explique comment tracer au mieux les traces 3D des mouvements des mains.
Le papier est payant, mais l'aperçu en haut à droite, intitulé "Regarde à l'intérieur>" sur l'image du livre, montre quelques tracés intéressants de différentes représentations de données de trace de main .

2
Volker Siegel