5. Linux 的力反馈

作者:

Johann Deneux <johann.deneux@gmail.com> 于 2001/04/22。

更新:

Anssi Hannula <anssi.hannula@gmail.com> 于 2006/04/09。

您可以重新分发此文件。请记得同时包含 shape.svg 和 interactive.svg。

5.1. 引言

本文档描述了如何在 Linux 下使用力反馈设备。其目标不是像对待简单的只输入设备那样支持这些设备(现在已经是这种情况),而是真正实现力效果的渲染。本文档仅描述 Linux 输入接口的力反馈部分。在进一步阅读本文档之前,请阅读 引言引言

5.2. 给用户的说明

要启用力反馈,您必须

  1. 配置内核时启用 evdev 和支持您设备的驱动程序。

  2. 确保已加载 evdev 模块并创建了 /dev/input/event* 设备文件。

在您开始之前,请允许我警告您,某些设备在初始化阶段会剧烈震动。例如,我的 “AVB Top Shot Pegasus” 就会出现这种情况。要停止这种烦人的行为,请将您的操纵杆移动到极限位置。无论如何,您应该始终将一只手放在您的设备上,以避免在出现问题时将其损坏。

如果您有一个串行 iforce 设备,则需要启动 inputattach。有关详细信息,请参见 引言

5.2.1. 它能工作吗?

有一个名为 fftest 的实用程序,可以用来测试驱动程序。

% fftest /dev/input/eventXX

5.3. 给开发人员的说明

所有交互都使用事件 API 完成。也就是说,您可以在 /dev/input/eventXX 上使用 ioctl() 和 write()。此信息可能会发生更改。

5.3.1. 查询设备功能

#include <linux/input.h>
#include <sys/ioctl.h>

#define BITS_TO_LONGS(x) \
        (((x) + 8 * sizeof (unsigned long) - 1) / (8 * sizeof (unsigned long)))
unsigned long features[BITS_TO_LONGS(FF_CNT)];
int ioctl(int file_descriptor, int request, unsigned long *features);

“request” 必须是 EVIOCGBIT(EV_FF, 功能数组的大小(以字节为单位))

返回设备支持的功能。features 是一个位域,具有以下位:

  • FF_CONSTANT 可以渲染恒力效果

  • FF_PERIODIC 可以渲染具有以下波形的周期性效果

    • FF_SQUARE 方波

    • FF_TRIANGLE 三角波

    • FF_SINE 正弦波

    • FF_SAW_UP 锯齿上升波

    • FF_SAW_DOWN 锯齿下降波

    • FF_CUSTOM 自定义波形

  • FF_RAMP 可以渲染斜坡效果

  • FF_SPRING 可以模拟弹簧的存在

  • FF_FRICTION 可以模拟摩擦

  • FF_DAMPER 可以模拟阻尼器效果

  • FF_RUMBLE 震动效果

  • FF_INERTIA 可以模拟惯性

  • FF_GAIN 增益可调

  • FF_AUTOCENTER 自动居中可调

注意

  • 在大多数情况下,您应该使用 FF_PERIODIC 而不是 FF_RUMBLE。所有支持 FF_RUMBLE 的设备都支持 FF_PERIODIC(方波、三角波、正弦波),反之亦然。

  • 目前 FF_CUSTOM 的确切语法未定义,因为还没有驱动程序支持它。

int ioctl(int fd, EVIOCGEFFECTS, int *n);

返回设备可以保存在其内存中的效果数量。

5.3.2. 将效果上传到设备

#include <linux/input.h>
#include <sys/ioctl.h>

int ioctl(int file_descriptor, int request, struct ff_effect *effect);

“request” 必须是 EVIOCSFF。

“effect” 指向一个描述要上传的效果的结构。效果被上传,但不会播放。effect 的内容可能会被修改。特别是,其字段 “id” 设置为驱动程序分配的唯一 id。此数据是执行某些操作(删除效果,控制播放)所必需的。为了告诉驱动程序分配新效果,用户必须将 “id” 字段设置为 -1。

效果是文件描述符特定的。

有关 ff_effect 结构的描述,请参见 <uapi/linux/input.h>。您还可以在文件 shape.svg 和 interactive.svg 中包含的一些草图中找到帮助。

../_images/shape.svg

形状

../_images/interactive.svg

交互

5.3.3. 从设备中删除效果

int ioctl(int fd, EVIOCRMFF, effect.id);

这会为设备内存中的新效果腾出空间。请注意,如果效果正在播放,这也会停止效果。

5.3.4. 控制效果的播放

播放的控制是通过 write() 完成的。以下是一个示例

 #include <linux/input.h>
 #include <unistd.h>

     struct input_event play;
     struct input_event stop;
     struct ff_effect effect;
     int fd;
...
     fd = open("/dev/input/eventXX", O_RDWR);
...
     /* Play three times */
     play.type = EV_FF;
     play.code = effect.id;
     play.value = 3;

     write(fd, (const void*) &play, sizeof(play));
...
     /* Stop an effect */
     stop.type = EV_FF;
     stop.code = effect.id;
     stop.value = 0;

     write(fd, (const void*) &stop, sizeof(stop));

5.3.5. 设置增益

并非所有设备的强度都相同。因此,用户应根据他们希望效果的强度来设置增益因子。此设置在访问驱动程序时会保持持久。

/* Set the gain of the device
int gain;           /* between 0 and 100 */
struct input_event ie;      /* structure used to communicate with the driver */

ie.type = EV_FF;
ie.code = FF_GAIN;
ie.value = 0xFFFFUL * gain / 100;

if (write(fd, &ie, sizeof(ie)) == -1)
    perror("set gain");

5.3.6. 启用/禁用自动居中

在我看来,自动居中功能会严重干扰效果的渲染,我认为它应该是一种效果,其计算取决于游戏类型。但是,如果您愿意,可以启用它。

int autocenter;             /* between 0 and 100 */
struct input_event ie;

ie.type = EV_FF;
ie.code = FF_AUTOCENTER;
ie.value = 0xFFFFUL * autocenter / 100;

if (write(fd, &ie, sizeof(ie)) == -1)
    perror("set auto-center");

值为 0 表示 “无自动居中”。

5.3.7. 动态更新效果

按照您想要上传新效果的方式进行操作,只不过您不是将 id 字段设置为 -1,而是将其设置为所需的效果 id。通常,效果不会停止并重新启动。但是,根据设备的类型,并非所有参数都可以动态更新。例如,iforce 设备无法更新效果的方向。在这种情况下,驱动程序会停止效果,上传它,然后重新启动它。

因此,建议仅在可以以回放计数 1 重新启动效果时,在效果播放时动态更改方向。

5.3.8. 有关效果状态的信息

每次效果的状态更改时,都会发送一个事件。事件字段的值和含义如下:

struct input_event {
/* When the status of the effect changed */
        struct timeval time;

/* Set to EV_FF_STATUS */
        unsigned short type;

/* Contains the id of the effect */
        unsigned short code;

/* Indicates the status */
        unsigned int value;
};

FF_STATUS_STOPPED   The effect stopped playing
FF_STATUS_PLAYING   The effect started to play

注意