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

我为一个基金会工作,该基金会旨在提高人们对互联网无障碍的认识。为了演示,我们想提供一个小型研讨会,模拟不同的残疾/缺陷。这是通过一个专门为这次演示创建的网站来完成的。

其中一个被证实的缺陷是有震颤,这意味着经历颤抖,难以控制的手部运动。由于这种缺陷,当鼠标在链接上时,很难准确地移动鼠标光标并按下鼠标按钮。一些老年人和有疾病的人,如帕金森氏症患者,都可能患有震颤。

现在我想以一种不可预测的方式移动鼠标光标,这样人们就很难点击一个小按钮。因为JavaScript不允许直接移动鼠标光标,所以我正在寻找其他方法来实现这一点。我有以下想法:

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

虽然第一个想法很酷,但我找不到这样的工具,无论是Mac还是Windows。我自己也没有任何编程技能。

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

有人有别的想法吗?

10237 次浏览

我使用指针锁定API做了一个快速的演示,希望您能够在此基础上编写代码。

我fork 这个指针锁演示回购并修改它以添加一个随机移动元素。

这是我的GitHub页面的链接:https://aristocrates.github.io/pointer-lock-demo
这里是我的repo的链接: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);

还有很多地方你可以改进,但希望这能帮助你开始。

非javascript方法

实际上,我喜欢基于javascript的解决方案,因为它们更有可能与web相关,而且很有可能与操作系统无关。然而,我在想-如何解决所有浏览器的问题,因为javascript解决方案,在这种情况下,将很难调整为所有可能的浏览器(我不确定是否有可能)。

所以,正如你所提到的,还有另一种方法——即在操作系统级别上模拟行为。这也有另一个好处——你可以确定对于浏览器来说,它看起来是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.c是你的C源代码文件的名称,那么你将得到可执行文件,在你的目录中称为m。大多数情况下,你需要权限直接写入鼠标设备,所以你可以使用sudo:

user@host:/path$ sudo ./m

其他操作系统

逻辑将保持不变:

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

就是这样。例如,Mac OS有自己的方式来处理鼠标(不像Linux, Mac也没有procfs),它被很好地描述为在这里

作为结论

哪个更好——javascript还是面向设备的解决方案——取决于你,因为在这种情况下,某些条件(比如跨浏览器或跨操作系统)可能决定一切。因此,我提供了一些指导原则,以及一些如何在操作系统级别上实现它的工作示例。这里的好处是解决方案是跨浏览器的,但代价是我们有操作系统绑定的程序。

你可以使用老年模拟套装,比如文章中描述的…我怀疑手颤抖的部分只是一个振动电机绑在手腕上,加上一些厚手套,使手通常笨拙。

这只是一个让震颤“正确”的想法,你可以记录一个真实病人的鼠标运动,这使它更真实,当你告诉人们数据来自哪里。

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

如果可以的话,请让它基于网络,这样你会接触到更多的人,而不是让他们安装一个程序或激活flash或其他任何东西。

你不能指望任何人都能把他们的手握得非常稳定,所以你可以考虑的一件事是,

  1. 向用户解释你在做什么,
  2. 让演示页面上的可点击元素比正常情况下要小得多。
  3. 将示例系统上的鼠标灵敏度提高到最大。

我的理由是(注意,我不是用户体验或医学专家)通过缩小可点击元素,你为大多数人创造了一个类似的问题,患有帕金森病的人每天都会面对一个网站。

而不是试图移动指针,你可以移动应用程序(网页)。我写了一个简单的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”)来调整形式移动。

我曾经在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

我犯了一个错误,我自己点击了它,而不是从命令行运行它,很快就发现这是多么令人沮丧。我试了几次才打开一个终端窗口来杀死它。

你的第二个想法(隐藏光标)是一个我认为可能很适合你的想法的一半:

  • 如您所建议的,通过CSS隐藏鼠标光标。(cursor:none IIRC)
  • 使用一些图像+ CSS绝对定位+ JS来模拟鼠标指针,而不是一个晃动光标的GIF;也就是说,沿着鼠标在页面上移动,并在鼠标光标所在的位置放置光标图像。

然后,在光标代码中添加一些震颤数学,以“;shake"光标。由你来决定什么是正确的曲线来正确地模拟震颤输入。

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

  • 捕捉点击事件,轻推它们到当前的“震颤”;位置——基于您的震颤曲线和边界的状态——检查您的元素,看看用户是否已经摆脱了预期的元素,或者可能进入了一个不是预期的元素。

你的“摇摇晃晃的光标”将显示在触摸设备上,这将没有一个光标开始。


编辑:

基于Michael Theriot的(非常干净和有用!)评论中的基本JSFiddle,这里有一个不断抖动的正态分布扫描当前光标位置:http://jsfiddle.net/benmosher/0x4mc64v/4/

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

为什么不使用硬件解决方案呢?有一些特定的鼠标你可以添加重量,比如罗技G500。不放重物,而是放一个小的振荡马达,让鼠标轻微摇晃。这也更加模拟了实际的混乱:不仅仅是光标在抖动,而是整个手和鼠标都在抖动。这也意味着你可以展示网站以外的其他软件。

你也可以把一些东西粘在鼠标上,而不是带重量槽的鼠标,但这样更明显。

因为你正在考虑用一个自定义鼠标驱动程序,我想在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);
}

这是我的xdotool脚本的windows版本,使用AutoIt。这是我的第一个AutoIt脚本,只花了几分钟就写好了,所以我相信它可以改进。只需保存扩展名。au3并使用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

控制

  • Home:开始模拟。
  • pause:暂停模拟。
  • Esc:退出模拟。

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

模拟地震的低水平部分现在已经很好地解决了。我将添加一些专注于模拟的震颤类型的东西:

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

这应该可以很好地满足用例,使它难以点击一个特定的区域,如按钮。

对于模拟帕金森病震颤引起的UI问题这一更普遍的问题,至少实际模拟这种震颤的手部运动是有趣的 我怀疑随机漫步可能不是一个很好的近似.

当然,它可能是震动运动的很难得到真正的手迹数据,但肯定有关于分析这种震动的论文:

论文帕金森病手部运动的参数化表征是关于如何最好地绘制3D手部运动轨迹 这篇论文是付费的,但在右上方的预览,在书的图像上标记为“深入>”,显示了一些不同的手迹数据的表示的有趣情节
  • 在你的DIV中,css隐藏光标使用cursor:none;
  • 创建一个。png光标图像,并用jQ在mousemove上移动它(lefttop)
  • 使用setTimeout随机。png margin-leftmargin-top (为了使重新定位顺利使用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>