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

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

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

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

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

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

有人有别的想法吗?


我做了一个快速的演示,希望你能够在此基础上编写代码,使用指针锁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);

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


非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代码中使用的不同,只需更改相应的行(因此,line with int fd = open("/dev/input/event4", O_RDWR);用你的设备代替事件

这里是这个程序的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或其他任何东西。


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

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

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


而不是试图移动指针,你可以移动应用程序(网页)。我写了一个简单的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隐藏鼠标光标。(光标:没有这个) 使用一些图像+ CSS绝对定位+ JS来模拟鼠标指针,而不是一个晃动光标的GIF;也就是说,沿着鼠标在页面上移动,并在鼠标光标所在的位置放置光标图像。

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

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

捕获单击事件,根据震颤曲线的状态将它们推到当前的“震颤”位置,并检查元素,看看用户是否已经摆脱了预期的元素,或者可能进入了预期之外的元素。

这个实现的一个主要好处是:你的“晃动的光标”将显示在触控设备上,而触控设备本来就没有光标。


编辑:

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

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


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

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


As you were thinking about doing it with a custom mouse driver I suppose a small program running on the PC would do either? If this is the case, here is a small snippet for C#, which infinitely moves the cursor randomly withing a range of plus minus 5px around the current cursor position. After each displacement the program waits 50 ms to 100 ms (not accurate!). The shakiness can be configured by adapting the values for the displacement and the pauses. I ran this in a console application and - depending on the values - it gave me quite a hard time stopping the program.

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脚本使用AutoIt的windows版本。这是我的第一个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问题的更普遍的问题,至少实际模拟这种震颤的手部运动是有趣的。 我怀疑随机游走可能不是一个很好的近似。

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

帕金森病患者手部运动的参数化表示是关于如何绘制手部运动的三维轨迹。 这篇论文是付费的,但右上方的预览图,在书的图片上标记为“看>”,展示了一些有趣的手迹数据的不同表示形式。


在你的DIV中,CSS-hide光标使用cursor:none; 创建一个。png光标图像,并使用鼠标移动的jQ移动它(左,上) 使用setTimeout随机化。png的margin-left和margin-top (使重新定位平滑使用CSS3过渡或做它与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>