javascript - Simulera skakningar (t.ex. från Parkinsons sjukdom) med musen på en webbplats?


Jag arbetar för en stiftelse som ökar medvetenheten om tillgänglighet på internet. För en presentation vill vi erbjuda en liten workshop som simulerar olika funktionsnedsättningar för människor. Detta görs via en webbplats som skapats speciellt för denna presentation.

En av de visade försämringarna är att ha en skakning, vilket betyder att man upplever darriga, svårkontrollerade handrörelser. Med denna försämring är det mycket svårt att flytta muspekaren exakt och att trycka på musknappen när musen är över en länk. Både vissa äldre och personer med sjukdom, t.ex. Parkinsons, kan drabbas av skakning.

Nu skulle jag vilja på något sätt flytta muspekaren på ett oförutsägbart sätt, så att det är mycket svårt för folk att klicka på en liten knapp. Eftersom JavaScript inte tillåter att flytta muspekaren direkt, letar jag efter andra sätt att uppnå detta. Jag kom på följande idéer:

  • Att använda en musdrivrutin/verktyg som simulerar att musen skakar.
  • Dölj muspekaren via CSS, placera en GIF-animation av en skakande muspekare på platsen för den ursprungliga pekaren (med JavaScript), och gör sedan mål-länken klickbar endast var några sekunder i ungefär en sekund. Detta skulle åtminstone ge känslan av att man alltid klickar vid fel ögonblick.

Medan den första idén skulle vara ganska cool, kunde jag inte hitta ett verktyg som detta, varken för Mac eller för Windows. Och jag har inga färdigheter i att programmera en sådan sak själv.

Den andra idén verkar lite klumpig, men den skulle uppnå önskad effekt, tror jag.

Har någon ett annat förslag?

Svar #1

Jag gjorde en snabb demo av något som du förhoppningsvis bör kunna basera din kod på, med hjälp av Pointer Lock API.

Jag har gafflat detta pointer-lock-demo-repo och ändrat det för att lägga till ett slumpmässigt rörelselement.

Här är länken till min GitHub-sida: https://aristocrates.github.io/pointer-lock-demo
Och här är länken till mitt repo: https://github.com/aristocrates/pointer-lock-demo

Den viktiga JavaScript-koden finns i app.js, i metoden canvasLoop(e).

Det enda jag ändrade från den ursprungliga demon var efter raderna

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

Jag lade till två rader för att representera slumpmässig rörelse:

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

Det finns fortfarande många saker du kan förbättra, men förhoppningsvis kan detta hjälpa dig att komma igång.

Svar #2

Icke-JavaScript-sätt

Faktiskt gillar jag lösningar som kan baseras på javascript, eftersom de med större sannolikhet är webbaserade och har goda chanser att vara plattformsoberoende. Jag funderade dock på hur man kan lösa ditt problem för alla webbläsare, eftersom javascript-lösningar i detta fall kommer att vara svåra att anpassa för alla möjliga webbläsare (jag är inte säker på om det är möjligt överhuvudtaget).

Så, som du har nämnt, finns det ett annat sätt — det vill säga att efterlikna beteendet på OS-nivå. Detta har också en annan fördel — du kan vara säker på att för webbläsaren ser det 100% ut som om det var mänskligt (för det är ju drivrutinen som skickar signalen). Så du kan använda drivrutin-/enhetsbaserade lösningar med vilken webbläsare som helst (eller till och med i situationer när javascript är inaktiverat).

Linux

Tyvärr medför inblandning av drivrutin/enhet omedelbart operativsystemberoende. Så för varje OS kommer du behöva en egen lösning. I detta inlägg fokuserar jag på en Linux-baserad lösning (så den fungerar med Linux) — och lite på Mac OS. Med Linux är det möjligt att skriva händelser till enheten explicit, så nedan är ett exempel på en funktion med huvudloop:

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

Min fullständiga kod för problemet kan hittas här. Programmet kommer att fråga efter amplituden av "skakning" och dess frekvens (alltså hur många mikrosekunder som är mellan "skakningarna"). För att efterlikna situationen kommer det att tvinga musen att röra sig slumpmässigt för 0..X punkter i slumpmässig riktning (upp-ned-vänster-höger) och sedan vänta slumpmässigt 0..Y mikrosekunder till nästa "skakning", där X är amplituden av "skakningen" och Y är frekvensen av "skakningen".

En annan sak kan vara att anpassa programmet för ditt system. Programmet är "dummy" och kan inte själv upptäcka musen, så "/dev/input/event4" är hårdkodat. För att ta reda på vad som kan vara identifieraren för ditt system kan du prova:

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

Så möjligheterna är "event3" och "event4" — men för ditt system kan det finnas andra värden. Så, om det skiljer sig från det som för närvarande används i C-kod, ändra bara motsvarande rad (dvs. raden med int fd=open("/dev/input/event4", O_RDWR); och sätt din enhet istället för event4)

En gif-demonstration för detta program (låg bildfrekvens, tyvärr, så håll bilden inte för stor) här.

En liten sidnotering (om du inte vet vad du ska göra med C-koden) — för att kompilera programmet ovan, använd bara:

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

där file.c är namnet på din C-källkodfil, då får du en körbar fil, kallad m i din katalog. Mest sannolikt behöver du behörighet att skriva direkt till musenheten, så du kan använda sudo:

user@host:/path$ sudo ./m

Andra operativsystem

Logiken kommer att förbli densamma:

  • Hitta ett sätt att få tillgång till din musenhet
  • Skriv händelse för att flytta musen
  • Tillämpa slumpmässighet på ditt evenemang

Det är allt. Till exempel har Mac OS sitt eget sätt att arbeta med musen (inte som Linux, Mac har inte heller procfs), det är väl beskrivet här.

Som en slutsats

Vad som är bättre — JavaScript eller enhetsorienterade lösningar — är upp till dig, eftersom vissa förhållanden (som korsad webbläsare eller korsade operativsystem) kan avgöra allt i detta fall. Därför har jag gett riktlinjer tillsammans med ett visst fungerande exempel på hur man implementerar det på OS-nivå. Fördelen här är att lösningen är korsad webbläsare, men som en kostnad har vi ett OS-bundet program.

Svar #3

Jag gjorde detta som ett skämt en gång, på Puppy Linux-forumet och fick kommentaren att:

Människor med Parkinson tror inte att det är roligt !!!

Botemedlet här är helt enkelt Ctrl-C, som tur är.

Här är shellscriptet som kräver 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

Namnge som parkinson_sim och kör med ett valfritt argument för tiden mellan skakningar som kan vara 0,001 till 999,0.

parkinson_sim [tid_mellan_skakningar_i_sekunder] #standard är 0,1

Jag gjorde misstaget att klicka på det själv istället för att köra det från kommandoraden och upptäckte snabbt hur frustrerande det måste vara. Det tog mig flera försök att få ett terminalfönster öppet för att avsluta det.

Svar #4

Din andra idé (att dölja markören) är halvvägs till en som jag tror kan fungera bra för dig:

  • Dölj muspekaren via CSS, som du föreslår. (cursor:none om jag minns rätt)
  • Istället för en skakig markör-GIF, använd någon bild + CSS absolut positionering + JS för att efterlikna muspekaren; alltså, följ musen runt sidan och placera markörbilden där muspekaren naturligt skulle vara.

Sedan lägger du till lite skakningsmatematik till din markörkod, för att "skaka" markören. Det är upp till dig att avgöra vilka kurvor som är rätt för att korrekt simulera skakningsinmatning.

Slutligen: för vilka kontroller du än programmerar (länkar, etc.):

  • fånga klickhändelser, knuffa dem till den aktuella "tremor"-platsen baserat på tillståndet i dina tremorkurvor, och kontrollera dina element för att se om användaren har skakat sig ur det avsedda elementet, eller möjligtvis in i ett element som inte var avsett.

En stor fördel med denna implementering: din 'skakiga markör' kommer att visas på pekskärmsenheter, som annars inte skulle ha en markör från början.


Redigera :

Baserat på Michael Theriots (mycket rena och hjälpsamma!) grundläggande JSFiddle från kommentarerna, här är en som skakar konstant med en normalt fördelad svepning runt den nuvarande markörens plats: http://jsfiddle.net/benmosher/0x4mc64v/4/

(normal-arrayen är resultatet av att köra rnorm(100) i min R-konsol. Det enklaste sättet jag kunde tänka mig i JS för att ta ett urval av ett normalt fördelat slumpmässigt heltal.)

Svar #5

Bara en idé för att få skakningen 'rätt', du kan spela in musens rörelse från en riktig patient, detta gör det mer autentiskt när du berättar för folk varifrån datan kommer.

Det finns skript för att låta en katt följa din muspekare, du skulle kunna justera ett för att låta en andra pekare följa (hoppa runt) din pekare. Sidan beräknar positionen för den andra pekaren, så den kan också avgöra om ett klickhändelse är framgångsrikt eller inte.

Om du kan, gör det gärna webbaserat, du når mycket fler människor på det här sättet än genom att be dem installera ett program eller aktivera flash eller vad det nu finns.

Svar #6

Istället för att försöka flytta pekaren, kan du flytta applikationen (webbsidan) istället. Jag skrev ett enkelt html-formulär som har några inmatningsfält i sig. När du flyttar musen över formuläret, rör sig formuläret.

Du kan se en demo av det rörliga formuläret på jsfiddle. Försök att klicka på ett av inmatningsfälten för att se effekten.

Jag använde jquery shake-effekten för att uppnå detta. Javascriptet för shake-effekten ser ut så här och gör bara att formuläret rör sig upp och ner när musen rörs över det:

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

Även om formen bara rör sig upp och ner, tror jag att den har önskad effekt. Du kan leka med parametrarna (riktning, gånger, avstånd, samt det o-nämnda "1000" ovan) för att justera formens rörelse.

Svar #7

Varför inte använda en hårdvarulösning? Det finns vissa möss som du kan lägga i vikter i, som Logitech G500. Istället för att lägga i en vikt, sätt i en liten oscillerande motor som gör att musen skakar lite. Detta simulerar också störningen mer verkligt: det är inte bara markören som skakar, utan hela handen och musen. Och det betyder också att du kan visa annan mjukvara än webbplatser.

Istället för en mus med en viktfack kan du också bara tejpa något på musen, men det är mer märkbart.

Relaterade artiklar