Simulating tremor (from e.g. Parkinson's Disea

2019-01-30 01:35发布

I'm working for a foundation that raises awareness for accessibility in the internet. For a presentation, we want to offer a small workshop that simulates different disabilities/impairments to people. This is done via a website created especially for this presentation.

One of the demonstrated impairments is having a tremor, which means experiencing shaky, difficult-to-control hand movements. With this impairment, it's very difficult to move the mouse cursor exactly and to press the mouse button while the mouse is over a link. Both some old people and people with disease, e.g. Parkinson's, can suffer from tremor.

Now I'd like to somehow move the mouse cursor in an unpredictable way, so that it's very hard for people to click on a small button. Because JavaScript doesn't allow moving the mouse cursor directly, I'm looking for other ways to achieve this. I came up with the following ideas:

  • Using a mouse driver / utility that simulates the mouse shaking.
  • Hide the mouse cursor via CSS, place a GIF animation of a shaking mouse cursor at the place of the original cursor (with JavaScript), and then make the target link clickable only every few seconds for a second or so. This would at least give the feeling as if one always clicks at the wrong moment.

While the first idea would be pretty cool, I couldn't find a tool like this, whether for Mac nor for Windows. And I don't have any skills in programming such a thing myself.

The second idea seems a bit clumsy, but it would achieve the desired effect, I think.

Does anybody have another idea?

13条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-01-30 02:10

Your second idea (hide the cursor) is halfway to one that I think may work well for you:

  • Hide the mouse cursor via CSS, as you suggest. (cursor:none IIRC)
  • Instead of a shaky-cursor GIF, use some image + CSS absolute positioning + JS to emulate the mouse pointer; i.e., follow the mouse around the page and plant the cursor image where the mouse cursor natively would be.

Then, you add some tremor math to your cursor code, to "shake" the cursor. Up to you to determine what the right curves are to properly simulate tremor input.

Finally: for whatever controls you are programming (links, etc.):

  • capture click events, nudge them to the current "tremor" location based on the state of your tremor curves, and bounds-check your elements to see if the user has shaken out of the element intended, or possibly into an element that was not intended.

One major bonus with this implementation: your 'shaky cursor' will be displayed on touch devices, which would not have a cursor to begin with.


Edit:

Based on Michael Theriot's (very clean and helpful!) base JSFiddle from the comments, here's one that tremors constantly with a normally-distributed sweep around the current cursor location: http://jsfiddle.net/benmosher/0x4mc64v/4/

(The normal array is the result of calling rnorm(100) in my R console. Simplest way I could think of in JS to sample a normally-distributed random integer.)

查看更多
你好瞎i
3楼-- · 2019-01-30 02:10

Just an idea for getting the tremor "right", you can record the mouse movement of a real patient, this makes it more authentic when you tell people where the data comes from.

There a scripts for letting a cat follow your mouse cursor, you could adjust one to let a second cursor follow (jump around) your cursor. The page is calculating the position of the the second cursor, so it can also determine if an click event is successful or not.

If you can, please make it web based, you will reach a lot more people this way than asking them to install a program or activate flash or whatever there is.

查看更多
够拽才男人
4楼-- · 2019-01-30 02:13

Instead of trying to move the pointer, you could move the application (web page) instead. I wrote a simple html form that has some entry fields in it. When you move the mouse onto the form, the form moves.

You can see a demo of the moving form at jsfiddle. Try to click on one of the input fields to see the effect.

I used the jquery shake effect to achieve this. The javascript for the shake effect looks like this, and just causes the form to move up and down whenever the mouse is moved over it:

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

Although the form only moves up and down, I think it has the desired effect. You can play with the parameters (direction, times, distance, as well as the un-named "1000" above) to tweak the form movement.

查看更多
时光不老,我们不散
5楼-- · 2019-01-30 02:15

Why not use a hardware solution? There are certain mice out there that you can put weights in, like the Logitech G500. Instead of putting in a weight, put in a small oscillating motor that makes the mouse shake slightly. This also simulated the actual disorder more: it's not just the cursor that shakes, but the entire hand and mouse. And it also means you can show other software than websites.

Instead of a mouse with a weight slot, you can also just tape something to the mouse, but that's more noticeable.

查看更多
beautiful°
6楼-- · 2019-01-30 02:16

I made a quick demo of something that you hopefully should be able to base your code on, using the Pointer Lock API.

I forked this pointer-lock-demo repo and modified it to add a random movement element.

Here is the link to my GitHub page: https://aristocrates.github.io/pointer-lock-demo
And here is the link to my repo: https://github.com/aristocrates/pointer-lock-demo

The javascript code of importance is contained in app.js, in the canvasLoop(e) method.

The only thing I changed from the original demo was after the lines

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

I added two lines to represent random movement:

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

There are still plenty of things you could improve, but hopefully this can help you get started.

查看更多
老娘就宠你
7楼-- · 2019-01-30 02:18

Non-javascript way

Actually, I like solutions, which may be based on javascript, since they are more likely web-related, and good chances are — OS-independent. However, I was thinking about — how to resolve your issue for all browsers, since javascript solutions, in this case, will be difficult to adjust for all possible browsers (I'm not sure if it's possible at all).

So, as you've mentioned, there is another way — i.e. to emulate the behavior on OS level. This has another advantage too — you may be sure that for browser it looks 100% as it was human (because, well, it's driver which is sending the signal). So you may use driver/device-based solutions with any browsers (or even in situation, when javascript is disabled).

Linux

Unfortunately, involving driver/device immediately causes OS dependency. So for each OS you'll need own solution. In this post I'm focused on Linux-based solution (so, will work with Linux) — and Mac OS a little. With Linux, it's possible to write events to device explicitly, so below is sample of function with main loop:

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

My full code for the issue be found here. The program will ask for amplitude of "tremor" and it's frequency (thus, how many time in micro-seconds are between "tremors"). To emulate situation, it will force mouse to move randomly for 0..X points in random direction (up-down-left-bottom) and wait randomly 0..Y micro-seconds till next "tremor", there X is amplitude of "tremor" and Y is frequency of "tremor"

Another thing may be to adapt the program for your system. The program is "dummy" and can't detect mouse by itself, so "/dev/input/event4" is hard-coded. To realize what may be identifier for your system you may try:

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

And so possibilities are "event3" and "event4" — but for your system that may have other values. So, if that is different from currently used in C code, just change the corresponding line (so, line with int fd = open("/dev/input/event4", O_RDWR); and place your device instead of event4)

A gif demo for this program (low frame rate, unfortunately, so keep image not too large) here.

A little side note (if you don't know what to do with C code) — to compile program above, just use:

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

where file.c is the name of your C source code file, then you'll get executable, called m in your directory. Most likely you'll need permissions to write into mouse device directly, so you may use sudo:

user@host:/path$ sudo ./m

Other OS

The logic will remain same:

  • Find a way to access your mouse device
  • Write event of moving mouse
  • Apply randomization to your event

That's it. For instance, Mac OS has its own way to work with mouse (not like Linux, Mac hasn't procfs as well), it's well-described here.

As a conclusion

What is better — javascript or device-oriented solutions — is up to you, because certain condition (like cross-browser or cross-OS) may decide everything in this case. Therefore, I've provided guidelines together with certain working example of how to implement that on OS level. The benefit here is that solution is cross-browser, but as a cost we have OS-binded program.

查看更多
登录 后发表回答