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. 给用户的说明¶
要启用力反馈,您必须
配置内核时启用 evdev 和支持您设备的驱动程序。
确保已加载 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 中包含的一些草图中找到帮助。
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
注意
只有 iforce 驱动程序支持状态反馈。如果您有充分的理由使用它,请联系 linux-joystick@atrey.karlin.mff.cuni.cz 或 anssi.hannula@gmail.com,以便将其添加到其余驱动程序中。