在网页上用鼠标模拟震颤(例如帕金森氏病)?


204

我正在为一个提高人们对互联网可访问性意识的基金会工作。对于演示,我们希望提供一个小型研讨会,模拟不同的残疾人士/残障人士。这是通过专门为此演示文稿创建的网站完成的。

表现出的一种障碍是震颤,这意味着手部动作难以控制。由于存在这种缺陷,很难精确地移动鼠标光标并在鼠标悬停在链接上时按鼠标按钮。一些老年人和帕金森氏症等疾病患者都可能患有震颤。

现在,我想以某种无法预测的方式移动鼠标光标,这样人们很难点击一个小按钮。由于JavaScript不允许直接移动鼠标光标,因此我正在寻找实现此目的的其他方法。我提出了以下想法:

  • 使用模拟鼠标晃动的鼠标驱动程序/实用程序。
  • 通过CSS隐藏鼠标光标,将摇动的鼠标光标的GIF动画放置在原始光标的位置(使用JavaScript),然后使目标链接每隔几秒钟单击一次。这至少会给人一种好像总是在错误的时刻点击的感觉。

尽管第一个想法很酷,但无论是Mac还是Windows,我都找不到这样的工具。而且我自己没有编程任何这类技能。

第二个想法似乎有些笨拙,但我认为它将达到预期的效果。

有人有其他想法吗?


35
您实际上可以使用Pointer Lock API
Stuart P. Bentley

2
尝试查看developer.mozilla.org/en-US/docs/Web/API/…。演示的直接链接是mdn.github.io/pointer-lock-demo。只要您愿意告诉用户在画布上单击并允许页面禁用鼠标光标,您就可能希望以此作为基础代码
Aristocrates 2014年

5
这个问题提高了我们Web开发人员的意识。感谢您的询问!您认为一个按钮应该多大才能被单击?
Ideogram

4
只是一个关于震颤的水平设定:有两种基本类型-“基本震颤”和帕金森氏震颤-它们是完全不同的。“本质性震颤”(并非纯粹是老年人的状况),是一种“意图性”震颤,这意味着只有在个人尝试做某事时,它才会显现出来,而个人越难以控制它,情况就会变得越糟。另一方面,PD震颤主要发生在休息时,当个体尝试做某事时,震颤通常并不明显(尽管很可能会出现PD引起的僵硬)。
Hot Licks

2
我发布了一个使用xdotool来控制鼠标的linux版本,但是Windows有一个类似的工具叫做autoit。它看起来非常简单,甚至还有一个标签[autoit]。也听起来您需要2个版本。一个摇动更多,直到运动开始,然后平静下来,而另一个摇动相对稳定,直到运动开始。
technosaurus

Answers:


148

我使用Pointer Lock API对您希望可以将代码作为基础的内容进行了快速演示。

我分叉了这个指针锁定演示存储库,并对其进行了修改以添加一个随机移动元素。

这是我的GitHub页面的链接:https : //aristocrates.github.io/pointer-lock-demo
这是我的仓库的链接:https : //github.com/aristocrates/pointer-lock-demo

重要的JavaScript代码包含在app.js,在canvasLoop(e)方法。

我从原始演示中更改的唯一一件事是在排队之后

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

我添加了两行来代表随机运动:

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

您仍然可以改善很多事情,但是希望这可以帮助您入门。


36
作为该功能的注释,随机移动与握手不同。通过随机移动,指针可以在屏幕上漂移。握手时,指针将围绕中心点振动。
zzzzBov 2014年

5
值得注意的是,浏览器对Pointer Lock Api的支持不是很好-在Internet Explorer或Safari中将无法使用。
史蒂夫·桑德斯

3
我没有时间自己尝试一下,但是也许您知道这一点:指针锁定API是否也可以在画布外部使用?还是仅限于画布?
2014年

8
一个更现实的实现将跟踪光标的“真实”位置,并在该位置周围的一个圆圈内随机移动,但这可能太复杂了。
tckmn

1
@Chris Chrome现在抛出Blocked pointer lock on an element because the element's frame is sandboxed and the 'allow-pointer-lock' permission is not set.。似乎jsFiddle将内容嵌入到沙盒框架中(即,不允许通过锁定指针 <iframe sandbox="webkit-allow-pointer-lock">,请参阅docs)。尝试将样本放在单个而不是沙盒的页面上。
ComFreek 2014年

36

非JavaScript方式

实际上,我喜欢可能基于javascript的解决方案,因为它们更可能与Web相关,并且很可能与OS无关。但是,我当时正在考虑-如何解决所有浏览器的问题,因为在这种情况下,很难针对所有可能的浏览器调整javascript解决方案(我不确定是否可能)。

因此,正如您所提到的,还有另一种方法-即在OS级别上模拟行为。这也有另一个优势-您可以确定,对于浏览器,它看起来像是人类的100%(因为,好吧,驱动程序正在发送信号)。因此,您可以在任何浏览器中使用基于驱动程序/设备的解决方案(甚至在禁用javascript的情况下)。

的Linux

不幸的是,涉及驱动程序/设备会立即导致操作系统依赖性。因此,对于每个操作系统,您都需要自己的解决方案。在本文中,我将重点介绍基于Linux的解决方案(因此,它将与Linux一起使用)以及Mac OS。使用Linux,可以将事件显式地写入设备,因此下面是带有主循环的函数示例:

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

完整的代码为这个问题找到这里。该程序将询问“震颤”的幅度及其频率(因此,“震颤”之间的间隔时间为微秒)。为了模拟情况,它将迫使鼠标0..X在随机方向(上下左右)上随机移动点,并随机等待0..Y几微秒直到下一个“震颤”,出现X“震颤”的幅度并且Y是“震颤” 的频率”

另一件事可能是使程序适合您的系统。该程序是“虚拟”程序,无法单独检测鼠标,因此"/dev/input/event4"是硬编码的。要了解什么可能是系统的标识符,您可以尝试:

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

可能性就这么大了"event3""event4"但是对于您的系统而言,可能还有其他价值。因此,如果与当前在C代码中使用的代码不同,则只需更改相应的行即可(因此,int fd = open("/dev/input/event4", O_RDWR);将替换为并放置您的设备,而不是event4

对这一计划的一个GIF演示(低帧频,遗憾的是,保持图像不是太大)这里

一点点注释(如果您不知道如何使用C代码)—要编译上面的程序,只需使用:

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

file.cC源代码文件的名称在哪里,那么您将获得可执行文件,m该文件在目录中被调用。您很可能需要权限才能直接写入鼠标设备,因此您可以使用sudo

user@host:/path$ sudo ./m

其他作业系统

逻辑将保持不变:

  • 找到一种访问鼠标设备的方法
  • 写动鼠标事件
  • 将随机化应用于您的活动

而已。例如,Mac OS有自己的鼠标处理方式(与Linux不同,Mac也不procfs一样),在此处对此进行了详细说明。

作为结论

更好的方法(JavaScript或面向设备的解决方案)由您决定,因为在这种情况下,某些条件(例如跨浏览器或跨OS)可能会决定一切。因此,我提供了指导方针以及如何在OS级别上实现该目标的某些工作示例。这样做的好处是解决方案是跨浏览器的,但是作为代价,我们有OS绑定程序。


非常感谢这篇非常详细的帖子。我怀疑我们将在平板电脑(Android或iOS)上进行演示,因此我们将无法在操作系统级别更改鼠标行为。但是反正很有趣!
2014年

53
您将如何在触摸屏设备上演示摇晃的鼠标?
Davor 2014年

6
@Davor老实说,我非常怀疑那些确实会感到震颤/ 手抖的人会使用触摸设备,除非他们想故意使自己发疯。
克里斯·西里菲斯

2
@ChrisCirefice:或被迫这样做,因为他们不得不使用其中的一种专门用于改善我们生活并使用触摸屏的设备。那。
PlasmaHH 2014年

@PlasmaHH OP并没有提到这是为了提高患有震颤及其困难(特别是使用触摸屏设备)的人们的意识。再说一次,我认为没有真正颤抖问题的人有足够的自虐能力去尝试使用手持式触摸屏设备。有些设备更易于使用,例如带有大(机械)按钮的电话。大多数操作系统都包括通过语音导航(例如,语音识别-Windows OS)。我认为受灾严重的人会使用这些工具代替iPhone。
克里斯·西里菲斯

23

我曾经在Puppy Linux论坛上开过一个玩笑,得到的评论是:

患有帕金森氏症的人不会觉得这很有趣!

幸运的是,这里的治愈方法只是cntrl-C。

这是需要xdotool的shell脚本

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

命名为parkinson_sim,并使用可选参数运行两次之间的震颤时间,该时间可以为0.001至999.0。

parkinson_sim [time_between_tremors_in_seconds]#默认为0.1

我犯了一个错误,那就是自己单击它而不是从命令行运行它,然后迅速发现它必须令人沮丧。我花了几次尝试才能打开终端窗口以杀死它。


1
您可能想用“ sleep 0.01”代替冒号来限制cpu的使用和速度,因为在我的装备上,它会使代码不切实际地快速跳转。
2014年

1
@nonchip-感谢您提供信息,我从来没有花足够长的时间来找出CPU的使用情况。为身体增加了睡眠。
Technosaurus

您知道在大多数Linux发行版中都可以使用键盘命令打开终端,对吗?
justhalf 2014年

@justhalf在当时的默认Puppy中,终端快捷方式是`在ROX-Filer窗口中按。尝试几次后才打开它,所以我用键盘打开了菜单。不久之后,我使用Pocketsphinx_continuous和大约10行外壳程序创建了一个基本的语音控制守护程序。
technosaurus

while :; do ...; sleep $time; done应该几乎总是while sleep $time; do ...; done,因为当用户按下Ctrl-C时,当前正在执行的命令几乎肯定会是sleep,而shell并不一定会在用户想要时结束脚本。这在交互式shell中的测试期间最明显发生,但有时甚至在脚本中也可能发生。更好的是while xdotool ... && xdotool ... && sleep ...; do :; done

16

您的第二个想法(隐藏光标)距离我认为适合您的想法的一半:

  • 根据您的建议,通过CSS隐藏鼠标光标。(cursor:noneIIRC)
  • 可以使用一些图像+ CSS绝对定位+ JS来模拟鼠标指针,而不是摇晃的GIF。即,跟随鼠标在页面周围,将光标图像植入鼠标光标本应放置的位置。

然后,将一些震颤数学添加到光标代码中,以“摇动”光标。由您决定正确的曲线是什么,以正确模拟震颤输入。

最后:对于您正在编程的任何控件(链接等):

  • 捕获点击事件,根据震颤曲线的状态将其微移到当前的“震颤”位置,然后对元素进行边界检查,以查看用户是否已经摆脱了预期的元素,或者是否陷入了预期之外的元素。

该实现的一个主要好处是:“摇晃的光标”将显示在没有光标的触摸设备上。


编辑:

基于Michael Theriot(非常干净而且很有帮助!)基于JSFiddle的注释,以下是在当前光标位置周围以正态分布的扫描不断震颤的一种:http : //jsfiddle.net/benmosher/0x4mc64v/4/

(该normal数组是rnorm(100)在我的R控制台中调用的结果。我可以想到在JS中采样正态分布的随机整数的最简单方法。)


一些标准JS鼠标事件信息:javascript.info/tutorial/...
本·毛思迪

谢谢,这确实是我的想法非常值得的补充。
2014年

小提琴对于我正在研究的项目来说简直是美丽,尽管它已经有4年了,您是否会介意我将它作为我项目的一部分进行帕金森模拟的基础?
格雷厄姆·里奇

@GrahamRitchie:我没意见,但迈克尔塞里奥特了大部分虽然IIRC😄的工作
本·毛思迪

14

只是使震颤“正确”的一个想法,您可以记录真实患者的鼠标移动,这在告诉人们数据来自何处时更加真实。

有一个脚本可以让猫跟随您的鼠标光标,您可以调整一个脚本以让第二个光标跟随(跳转)您的光标。该页面正在计算第二个光标的位置,因此它还可以确定单击事件是否成功。

如果可以的话,请使其成为基于网络的网站,这样一来,与要求他们安装程序或激活Flash或其他功能的人相比,您会接触到更多的人。


感谢您的建议。
约书亚·穆海姆

1
我确实喜欢这个想法-可以通过JavaScript在任何时间间隔记录鼠标的位置。然后,您可以绘制运动(XY平面),甚至可以获得一些基本统计信息,以获取Pointer Lock API解决方案的“ tremor_randomness”更有效的公式或类似的东西。这将需要更多的工作(例如,每100毫秒仅获取XY位置10秒钟)和分析,但是与简单的随机化相比,它会给您更真实的效果。为了您的事业,这可能是值得的。
克里斯·西里菲斯

10

除了尝试移动指针外,还可以移动应用程序(网页)。我写了一个简单的HTML表单,其中包含一些输入字段。当您将鼠标移到窗体上时,窗体将移动。

您可以在jsfiddle上看到移动表单的演示。尝试单击输入字段之一以查看效果。

我使用了jQuery 震动效果来实现这一点。抖动效果的javascript看起来像这样,每当鼠标移到上方时,它都会导致表单上下移动:

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

尽管表格仅上下移动,但我认为它具有预期的效果。您可以使用参数(方向,时间,距离以及上面未命名的“ 1000”)进行调整,以调整表单移动。


3
我本人也考虑过这一点,但是虽然易于实现,但并没有显示出震颤的“真实”体验。
约书亚·穆海姆

10

为什么不使用硬件解决方案?有一些可以放重物的老鼠,例如Logitech G500。不用增加重量,而要使用小型振动马达,这会使鼠标稍微摇动。这也更多地模拟了实际的疾病:不仅是光标在晃动,而且是整个手和鼠标。这也意味着您可以显示网站以外的其他软件。

除了使用带配重槽的鼠标,您还可以将一些东西粘在鼠标上,但这更引人注意。


因为我是计算机狂,而不是机械狂,所以我会坚持使用电子解决方案。谢谢!
2014年

尽管可能的硬件解决方案是通过向鼠标(可能是有线鼠标)添加随机噪声发生器来对其进行调试。
Hot Licks

6

当您考虑使用自定义鼠标驱动程序进行操作时,我想在PC上运行一个小程序就能做到吗?如果是这种情况,这是C#的一小段代码,它可无限随机地将光标移动到当前光标位置周围的正负5px范围内。每次位移后,程序将等待50毫秒至100毫秒(不准确!)。可以通过调整位移和暂停的值来配置抖动。我在控制台应用程序中运行了该程序,根据值,这使我很难停止该程序。

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

这是使用AutoIt的 xdotool脚本的Windows版本。这是我有史以来第一个AutoIt脚本,只花了几分钟的时间编写,因此我相信它可以得到改进。只需保存扩展名.au3并使用AutoIt(运行脚本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

控制项

  • 主页:开始仿真。
  • 暂停:暂停模拟。
  • Esc:退出模拟。

或者从这里使用我的编译版本。


非常好。谢谢!
2014年

5

您不能指望有人能够完全稳定地握住他们的手,所以您可以考虑的一件事是,

  1. 向用户说明您在做什么,
  2. 使演示页面上的可单击元素比平常小得多。
  3. 最大限度地提高示例系统上的鼠标灵敏度。

我的推论是(谨慎,我不是UX或医学方面的专家)通过使可点击元素变小,您对大多数人造成了类似的问题,即遭受帕金森氏病折磨的人在日常的网站上都会面对。


这也是一个有趣的想法。无论如何,我确实计划将可点击元素做得很小。
约书亚·穆海姆

2
恐怕大多数鼠标用户只要集中精力,就可以将其设备控制在1-2像素以下-例如,使用我使用的鼠标设置,手的晃动低于1像素。因此,如果您的按钮大于1-2像素,则可能不是通用解决方案...
Jonas Heidelberg 2014年

我将添加#3,提高鼠标速度并单击设置以达到最大值
Ryan B

在鼠标上具有某种“自动音量控制”是有道理的,它可以放大较小的动作,同时使较大的动作更接近“正常”。
热门点击2014年

4

您可以使用养老模拟西装,比如一个在描述文章......我怀疑手震颤部分只是绕在手腕上绑一个振动马达,再加上一些厚手套,使手一般笨拙。


谢谢。尽管这很有趣,但我们可能没有钱和时间让每个访客都穿上西装。;)
约书亚·穆海姆

5
这难道不适合作为评论吗?
Selali Adob​​or 2014年

好吧,我对javascript和html标签有些困惑,但是由于询问者还建议使用特殊的鼠标驱动程序(然后提到的平板电脑),因此似乎欢迎其他解决方案。一旦消除了特定的技术限制,这就是答案。这确实是该领域研究人员解决模拟与年龄相关的残疾问题的方式。我还认为,如果您只想颤抖,那可以相对便宜地自己动手做-那些魔术贴的手腕重物和一个振动的马达,应该不会太难。
user3067860 2014年

4
  • 在您的DIVCSS中,使用cursor:none;
  • 创建一个.png光标图像,并在jQ上将其移动(lefttopmousemove
  • 随机化.png margin-leftmargin-top使用setTimeout (使用CSS3 transition或使用jQ 使重新定位平滑.animate())。

注意:脚本无法知道手是否仍在鼠标上;)

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>


2

到目前为止,模拟震颤的低级部分已经得到很好的回答。我将添加一些关于震颤的模拟对象:

大多数答案都实现了鼠标光标,该鼠标光标在随机路径上移动,并在X和Y方向上具有一些固定的最大步长。

对于很难打到特定区域(例如按钮)的用例,这应该足够好用。

对于模拟由帕金森氏病引起的震颤引起的UI问题的更一般的问题,至少是要实际模拟这种震颤的手部运动是很有趣的。
我怀疑随机游走可能不是一个很好的近似值

当然,可能很难掌握震颤运动的真实手部跟踪数据,但是肯定有关于分析这种震颤的论文:

本文在帕金森氏病的手部动作参数表示是关于如何最好情节3D手部运动的痕迹。
纸有付费用,但是右上角的预览在书本图像上标有“ Look Inside>”,显示了一些有趣的手迹数据表示形式

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.