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. 開發者須知

所有互動均使用 event 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, 功能陣列的大小,以位元組為單位)

返回裝置支援的功能。 功能是一個位域,包含以下位

  • 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

注意