it-swarm.com.de

Simulieren Sie Tremor (z. B. bei Parkinson) mit der Maus auf einer Webseite?

Ich arbeite für eine Stiftung, die das Bewusstsein für Barrierefreiheit im Internet schärft. Für eine Präsentation möchten wir einen kleinen Workshop anbieten, der unterschiedliche Behinderungen/Beeinträchtigungen von Menschen simuliert. Dies geschieht über eine eigens für diese Präsentation erstellte Website.

Eine der nachgewiesenen Beeinträchtigungen ist ein Zittern, was bedeutet, dass zitternde, schwer zu kontrollierende Handbewegungen auftreten. Mit dieser Beeinträchtigung ist es sehr schwierig, den Mauszeiger genau zu bewegen und die Maustaste zu drücken, während sich die Maus über einem Link befindet. Sowohl einige alte Leute als auch Leute mit Krankheit, z.B. Parkinson kann unter Zittern leiden.

Jetzt möchte ich den Mauszeiger irgendwie auf unvorhersehbare Weise bewegen, so dass es für die Leute sehr schwierig ist, auf eine kleine Schaltfläche zu klicken. Da JavaScript das direkte Bewegen des Mauszeigers nicht zulässt, suche ich nach anderen Möglichkeiten, um dies zu erreichen. Ich hatte folgende Ideen:

  • Verwenden eines Maustreibers/-dienstprogramms, das das Verwackeln der Maus simuliert.
  • Blenden Sie den Mauszeiger über CSS aus, platzieren Sie eine GIF-Animation eines zitternden Mauszeigers an der Stelle des ursprünglichen Cursors (mit JavaScript) und machen Sie den Ziel-Link dann etwa alle paar Sekunden für eine Sekunde anklickbar. Dies würde zumindest das Gefühl vermitteln, als würde man immer im falschen Moment klicken.

Während die erste Idee ziemlich cool wäre, konnte ich kein solches Tool finden, weder für Mac noch für Windows. Und ich kann so etwas nicht selbst programmieren.

Die zweite Idee scheint etwas ungeschickt, aber ich denke, sie würde den gewünschten Effekt erzielen.

Hat jemand eine andere Idee?

204
Joshua Muheim

Ich habe eine kurze Demo von etwas gemacht, auf das Sie Ihren Code hoffentlich mit der Pointer Lock API aufbauen können.

Ich gabelte dieses Zeigersperr-Demo-Repo und modifizierte es, um ein zufälliges Bewegungselement hinzuzufügen.

Hier ist der Link zu meiner GitHub-Seite: https://aristocrates.github.io/pointer-lock-demo
Und hier ist der Link zu meinem Repo: https://github.com/aristocrates/pointer-lock-demo

Der JavaScript-Code von Bedeutung ist in app.js In der canvasLoop(e) -Methode enthalten.

Das einzige, was ich von der ursprünglichen Demo geändert habe, war nach den Zeilen

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

Ich habe zwei Linien hinzugefügt, um zufällige Bewegungen darzustellen:

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

Es gibt noch viele Dinge, die Sie verbessern können, aber dies kann Ihnen hoffentlich den Einstieg erleichtern.

148
Aristocrates

Nicht-Javascript Weg

Eigentlich mag ich Lösungen, die auf Javascript basieren können, da sie mit größerer Wahrscheinlichkeit webbezogen sind und gute Chancen bestehen - Betriebssystemunabhängig. Ich dachte jedoch darüber nach, wie Sie Ihr Problem für alle Browser lösen können, da Javascript-Lösungen in diesem Fall nur schwer für alle möglichen Browser angepasst werden können (ich bin mir nicht sicher, ob dies überhaupt möglich ist).

Wie Sie bereits erwähnt haben, gibt es also einen anderen Weg - nämlich das Verhalten auf Betriebssystemebene zu emulieren. Dies hat auch einen weiteren Vorteil: Sie können sicher sein, dass der Browser zu 100% menschlich aussieht (weil der Treiber das Signal sendet). Sie können also treiber-/gerätebasierte Lösungen mit jedem Browser verwenden (oder sogar in Situationen, in denen Javascript deaktiviert ist).

Linux

Leider führt die Einbindung von Treiber/Gerät sofort zu einer Abhängigkeit vom Betriebssystem. Für jedes Betriebssystem benötigen Sie eine eigene Lösung. In diesem Beitrag konzentriere ich mich auf Linux-basierte Lösungen (wird also mit Linux funktionieren) - und ein wenig auf Mac OS. Unter Linux ist es möglich, Ereignisse explizit auf das Gerät zu schreiben. Im Folgenden finden Sie ein Funktionsbeispiel für die Hauptschleife:

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;
}

Mein vollständiger Code für das Problem ist zu finden hier . Das Programm fragt nach der Amplitude des "Zitterns" und seiner Frequenz (dh wie viel Zeit in Mikrosekunden zwischen "Zittern" liegt). Um eine Situation zu emulieren, wird die Maus gezwungen, sich nach dem Zufallsprinzip um 0..X Punkte in zufälliger Richtung (oben-unten-links-unten) zu bewegen und nach dem Zufallsprinzip 0..Y Mikrosekunden bis zum nächsten "Zittern" zu warten X ist die Amplitude von "Tremor" und Y ist die Frequenz von "Tremor"

Eine andere Möglichkeit ist, das Programm an Ihr System anzupassen. Das Programm ist "Dummy" und kann die Maus nicht selbst erkennen, daher ist "/dev/input/event4" Fest codiert. Um zu erkennen, welche Kennung für Ihr System verwendet werden kann, versuchen Sie Folgendes:

[email protected]:/path$ cat /proc/bus/input/devices | grep mouse
H: Handlers=mouse0 event3 
H: Handlers=mouse1 event4

Und so sind die Möglichkeiten "event3" Und "event4" - aber für Ihr System können andere Werte vorliegen. Wenn sich das von dem derzeit in C-Code verwendeten unterscheidet, ändern Sie einfach die entsprechende Zeile (also Zeile mit int fd = open("/dev/input/event4", O_RDWR); und platzieren Sie Ihr Gerät anstelle von event4).

Eine GIF-Demo für dieses Programm (niedrige Framerate, daher Bild nicht zu groß) hier .

Eine kleine Randnotiz (wenn Sie nicht wissen, was Sie mit C-Code machen sollen) - um das obige Programm zu kompilieren, verwenden Sie einfach:

[email protected]:/path$ gcc -std=gnu99 file.c -o m

wobei file.c der Name Ihrer C-Quellcodedatei ist, dann erhalten Sie die ausführbare Datei m in Ihrem Verzeichnis. Höchstwahrscheinlich benötigen Sie Berechtigungen, um direkt auf das Mausgerät schreiben zu können. Daher können Sie Sudo verwenden:

[email protected]:/path$ Sudo ./m

Anderes Betriebssystem

Die Logik bleibt gleich:

  • Finden Sie einen Weg, um auf Ihr Mausgerät zuzugreifen
  • Schreibe Ereignis der Mausbewegung
  • Wenden Sie die Randomisierung auf Ihre Veranstaltung an

Das ist es. Zum Beispiel hat Mac OS seine eigene Art, mit der Maus zu arbeiten (nicht wie Linux, Mac hat auch nicht procfs), es ist gut beschrieben hier) .

Als Schlussfolgerung

Was besser ist - Javascript oder geräteorientierte Lösungen - liegt an Ihnen, da in diesem Fall eine bestimmte Bedingung (z. B. Cross-Browser oder Cross-OS) alles entscheiden kann. Aus diesem Grund habe ich Richtlinien zusammen mit bestimmten Arbeitsbeispielen zur Implementierung auf Betriebssystemebene bereitgestellt. Der Vorteil hierbei ist, dass die Lösung browserübergreifend ist, wir jedoch ein an das Betriebssystem gebundenes Programm haben.

36
Alma Do

Ich habe das einmal als Scherz im Puppy Linux Forum gemacht und bekam die Bemerkung, dass:

Leute mit Parkinson werden es nicht lustig finden !!!

Heilung hier ist einfach Cntrl-C, zum Glück.

Hier ist das Shell-Skript, das xdotool benötigt

#!/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

Nennen Sie es als parkinson_sim und führen Sie es mit einem optionalen Argument für die Zeit zwischen den Erschütterungen aus, die 0,001 bis 999,0 betragen kann.

parkinson_sim [time_between_tremors_in_seconds] #default ist 0.1

Ich habe den Fehler gemacht, selbst darauf zu klicken, anstatt es über die Befehlszeile auszuführen, und schnell festgestellt, wie frustrierend es sein muss. Ich brauchte mehrere Versuche, um ein Terminalfenster zu öffnen, um es zu töten.

23
technosaurus

Ihre zweite Idee (den Cursor verstecken) ist auf halbem Weg zu einer Idee, von der ich denke, dass sie für Sie gut geeignet ist:

  • Verstecken Sie den Mauszeiger über CSS, wie Sie vorschlagen. (cursor:none IIRC)
  • Verwenden Sie anstelle eines Wackelcursor-GIFs etwas Bild + absolute CSS-Positionierung + JS, um den Mauszeiger zu emulieren. d.h. folgen Sie der Maus um die Seite und platzieren Sie das Cursorbild dort, wo sich der Mauszeiger ursprünglich befinden würde.

Dann fügen Sie Ihrem Cursor-Code etwas Zittern hinzu, um den Cursor zu "schütteln". Sie bestimmen, welche Kurven richtig sind, um die Tremoreingabe richtig zu simulieren.

Zum Schluss: für alle Steuerelemente, die Sie programmieren (Links usw.):

  • erfassen Sie Klickereignisse, bewegen Sie sie auf der Grundlage des Status Ihrer Tremorkurven an die aktuelle "Tremor" -Position und überprüfen Sie anhand der Begrenzungen Ihre Elemente, ob der Benutzer das beabsichtigte Element oder möglicherweise ein nicht beabsichtigtes Element verlassen hat .

Ein großer Vorteil bei dieser Implementierung: Ihr "wackeliger Cursor" wird auf Touch-Geräten angezeigt, die anfangs keinen Cursor hätten.


Bearbeiten:

Basierend auf Michael Theriots (sehr sauber und hilfsbereit!) Basis JSFiddle aus den Kommentaren, ist hier eine, die ständig mit einem normalverteilten Sweep um die aktuelle Cursorposition zittert: http://jsfiddle.net/benmosher/0x4mc64v/ 4 /

(Das Array normal ist das Ergebnis des Aufrufs von rnorm(100) in meiner R-Konsole. Die einfachste Möglichkeit, mir in JS ein Beispiel für eine normalverteilte zufällige Ganzzahl vorzustellen.)

16
Ben Mosher

Nur eine Idee, um das Zittern "richtig" zu machen: Sie können die Mausbewegung eines echten Patienten aufzeichnen. Dies macht es authentischer, wenn Sie den Menschen mitteilen, woher die Daten stammen.

Dort gibt es ein Skript, mit dem Sie eine Katze Ihrem Mauszeiger folgen lassen können. Sie können eines anpassen, damit ein zweiter Cursor Ihrem Cursor folgt (um ihn herumspringt). Die Seite berechnet die Position des zweiten Cursors, sodass auch festgestellt werden kann, ob ein Klickereignis erfolgreich war oder nicht.

Wenn Sie können, machen Sie es bitte webbasiert, Sie werden auf diese Weise viel mehr Leute erreichen, als sie zu bitten, ein Programm zu installieren oder Flash zu aktivieren oder was auch immer es gibt.

14
user3934260

Anstatt zu versuchen, den Zeiger zu verschieben, können Sie stattdessen die Anwendung (Webseite) verschieben. Ich habe ein einfaches HTML-Formular geschrieben, das einige Eingabefelder enthält. Wenn Sie die Maus auf das Formular bewegen, wird das Formular verschoben.

Sie können sehen eine Demo der sich bewegenden Form bei jsfiddle . Versuchen Sie, auf eines der Eingabefelder zu klicken, um den Effekt zu sehen.

Ich habe den Effekt jquery shake verwendet, um dies zu erreichen. Das Javascript für den Shake-Effekt sieht so aus und bewirkt, dass sich das Formular immer dann nach oben und unten bewegt, wenn die Maus darüber bewegt wird:

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

Obwohl sich die Form nur auf und ab bewegt, hat sie meiner Meinung nach den gewünschten Effekt. Sie können mit den Parametern (Richtung, Zeiten, Entfernung sowie der oben genannten "1000") spielen, um die Formularbewegung zu optimieren.

10
chue x

Warum nicht eine Hardwarelösung verwenden? Es gibt bestimmte Mäuse, in die Sie Gewichte einsetzen können, wie z. B. den Logitech G500. Setzen Sie statt eines Gewichts einen kleinen oszillierenden Motor ein, der die Maus leicht zittern lässt. Dies simulierte auch die tatsächliche Störung mehr: Es ist nicht nur der Cursor, der zittert, sondern die gesamte Hand und Maus. Und es bedeutet auch, dass Sie andere Software als Websites anzeigen können.

Anstelle einer Maus mit einem Gewichtsschlitz können Sie auch einfach etwas auf die Maus kleben, aber das fällt auf.

10
Nzall

Da Sie darüber nachgedacht haben, es mit einem benutzerdefinierten Maustreiber zu tun, würde ich annehmen, dass ein kleines Programm, das auf dem PC ausgeführt wird, dies auch tun würde? Wenn dies der Fall ist, finden Sie hier einen kleinen Ausschnitt für C #, der den Cursor in einem Bereich von plus minus 5px stufenlos um die aktuelle Cursorposition bewegt. Nach jeder Verschiebung wartet das Programm 50 ms bis 100 ms (nicht genau!). Die Wackeligkeit kann durch Anpassen der Werte für die Verschiebung und die Pausen konfiguriert werden. Ich habe dies in einer Konsolenanwendung ausgeführt und es fiel mir - abhängig von den Werten - ziemlich schwer, das Programm zu stoppen.

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

Hier ist eine Windows-Version meines xdotool-Skripts, das AutoIt verwendet. Dies war mein erstes AutoIt-Skript, und das Schreiben dauerte nur ein paar Minuten. Ich bin mir also sicher, dass es verbessert werden kann. Einfach mit der Erweiterung .au3 speichern und mit AutoIt (Run Script x86) ausführen.

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

Steuerelemente

  • Home: Simulation starten.
  • pause: Simulation anhalten.
  • Esc: Simulation beenden.

Oder verwende meine kompilierte Version von hier .

6
technosaurus

Sie können nicht erwarten, dass jemand seine Hände vollkommen ruhig hält.

  1. Erklären Sie den Benutzern, was Sie tun, und
  2. Verkleinern Sie die anklickbaren Elemente auf der Demo-Seite erheblich.
  3. Erhöhen der Mausempfindlichkeit auf dem Beispielsystem auf das Maximum.

Meine Argumentation lautet (Einschränkung, ich bin kein Experte für UX oder Medizin): Wenn Sie die klickbaren Elemente verkleinern, entsteht für die meisten Menschen ein ähnliches Problem, mit dem eine an Parkinson erkrankte Person auf einer alltäglichen Website konfrontiert wäre.

5
jdphenix
  • In Ihrem DIV CSS-verstecken Sie den Cursor mit cursor:none;
  • Erstelle ein .png Cursor Bild und verschiebe es (left, top) mit jQ auf mousemove
  • Randomisieren Sie die .png margin-left Und margin-top Mit einem setTimeout (um die Neupositionierung reibungslos zu gestalten, verwenden Sie CSS3 transition oder tun Sie dies mit jQ .animate()).

Hinweis: Das Skript kann nicht wissen, ob sich die Hand noch auf der Maus befindet.

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

Sie können einen Alterssimulationsanzug verwenden, wie in this article beschrieben. Ich vermute, der Handzitterteil ist nur ein Vibrationsmotor, der um das Handgelenk geschnallt ist, plus ein paar dicke Handschuhe machen die Hände in der Regel ungeschickt.

4
user3067860

Die Low-Level-Teile der Tremor-Simulation sind mittlerweile gut beantwortet. Ich werde etwas hinzufügen, das sich auf die Art von Tremor konzentriert, der simuliert werden soll:

Bei den meisten Antworten wird ein Mauszeiger implementiert, der sich auf einem zufälligen Pfad mit einer festgelegten maximalen Schrittweite in X- und Y-Richtung bewegt.

Dies sollte für den Anwendungsfall, dass es schwierig ist, einen bestimmten Bereich wie einen Knopf zu treffen, gut genug funktionieren.

Für das allgemeinere Problem der Simulation von UI-Problemen, die durch ein Zittern der Parkinson-Krankheit verursacht werden, wäre es zumindest interessant, die Handbewegungen dieser Art von Zittern tatsächlich zu simulieren.
Ich vermute, dass der zufällige Gang keine sehr gute Annäherung ist .

Es ist zwar schwierig, echte Handspurdaten der Tremorbewegung zu erhalten, aber es gibt mit Sicherheit Papiere zur Analyse dieser Art von Tremor:

Die Arbeit Parametrische Darstellung der Handbewegung bei Parkinson-Krankheit befasst sich mit der optimalen Darstellung von 3D-Handbewegungsspuren.
Das Papier ist kostenpflichtig, aber die Vorschau oben rechts mit der Aufschrift "Look Inside>" auf dem Buchbild zeigt einige interessante Diagramme verschiedener Darstellungen von Handspurdaten .

2
Volker Siegel