添加自定义控制器设备映射

游戏控制器库维护着一个内部控制器设备数据库,该数据库用于配置按钮、运动轴布局、已识别控制器的映射以及未识别控制器的默认映射。该数据库包含许多常用控制器,但可能不包含与特定游戏相关的所有设备。游戏控制器库支持通过以下功能进行自定义:

  • 检索当前映射数据库。
  • 向现有数据库添加条目。
  • 替换现有数据库条目。
  • 用新数据库替换整个当前数据库。

识别设备

控制器设备由其 productIdvendorId 值识别。每个已识别的控制器设备在数据库中至少有一个条目,其中包含匹配的 productIdvendorId。控制器映射结构包含指定条目限定的最小和最大 Android API 范围的字段。只要具有唯一的最小和最大 API 范围,数据库中就可以存在具有相同 productIdvendorId 的多个条目。

读取当前重映射数据

使用 Paddleboat_getControllerRemapTableData 函数检索当前重映射数据。

int32_t Paddleboat_getControllerRemapTableData(
   const int32_t destRemapTableEntryCount,
   Paddleboat_Controller_Mapping_Data* mappingData)

Paddleboat_getControllerRemapTableData 返回内部数据库中存在的重映射条目总数。

参数 说明
destRemapTableEntryCount 作为 mappingData 参数传入的 Paddleboat_Controller_Mapping_Data 元素的数组大小。
mappingData 指向 Paddleboat_Controller_Mapping_Data 元素数组的指针。

如果 destRemapTableEntryCount 小于重映射条目总数,则只有 destRemapTableEntryCount 指定的条目数量会被复制到 mappingData 中。

添加或替换重映射数据

使用 Paddleboat_addControllerRemapData 函数添加重映射条目,或替换当前重映射数据库。

void Paddleboat_addControllerRemapData(
   const Paddleboat_Remap_Addition_Mode addMode,
   const int32_t remapTableEntryCount,
   const Paddleboat_Controller_Mapping_Data* mappingData)
参数 说明
addMode 操作中使用的添加规则。有效值为 PADDLEBOAT_REMAP_ADD_MODE_DEFAULTPADDLEBOAT_REMAP_ADD_MODE_REPLACE_ALL
remapTableEntryCount 作为 mappingData 参数传入的 Paddleboat_Controller_Mapping_Data 元素的数组大小。
mappingData 指向 Paddleboat_Controller_Mapping_Data 元素数组的指针。

添加模式

如果在 addMode 中指定了 PADDLEBOAT_REMAP_ADD_MODE_REPLACE_ALL,现有数据库将被删除并替换为新数组的内容。

如果在 addMode 中指定了 PADDLEBOAT_REMAP_ADD_MODE_DEFAULT,则以下条件将应用于作为 mappingData 传入的数组中的每个元素:

  • 如果 Paddleboat_getControllerRemapTableData 是唯一的(换句话说,vendorIdproductId 尚不存在,或者确实存在但具有不重叠的 minApimaxApi 范围),则该条目将添加到内部数据库中。
  • 如果 Paddleboat_getControllerRemapTableData 不唯一(vendorIdproductId 已存在,并且 minApimaxApi 存在重叠),它将*替换*内部数据库中的现有条目。

Paddleboat_Controller_Mapping_Data 结构是

typedef struct Paddleboat_Controller_Mapping_Data {
    int16_t minimumEffectiveApiLevel; /** Min. API level for this entry */
    int16_t maximumEffectiveApiLevel; /** Max. API level, 0 = no max */
    int32_t vendorId; /** VendorID of the controller device for this entry */
    int32_t productId; /** ProductID of the controller device for this entry */
    int32_t flags; /** Flag bits, will be ORed with
                     * Paddleboat_Controller_Info.controllerFlags */

    /** AMOTION_EVENT_AXIS value for the corresponding Paddleboat control axis,
     *  or PADDLEBOAT_AXIS_IGNORED if unsupported. */
    uint16_t axisMapping[PADDLEBOAT_MAPPING_AXIS_COUNT];
    /** Button to set on positive or negative axis value,
     *  PADDLEBOAT_AXIS_BUTTON_IGNORED if none. */
    uint8_t axisPositiveButtonMapping[PADDLEBOAT_MAPPING_AXIS_COUNT];
    uint8_t axisNegativeButtonMapping[PADDLEBOAT_MAPPING_AXIS_COUNT];
    /** AKEYCODE_ value corresponding with the corresponding Paddleboat button.
     *  PADDLEBOAT_BUTTON_IGNORED if unsupported. */
    uint16_t buttonMapping[PADDLEBOAT_BUTTON_COUNT];
} Paddleboat_Controller_Mapping_Data;

映射示例

以下内容展示了一个用于描述 Google Stadia 控制器Paddleboat_Controller_Mapping_Data 填充示例

#define PADDLEBOAT_AXIS_BUTTON_DPAD_UP 0
#define PADDLEBOAT_AXIS_BUTTON_DPAD_LEFT 1
#define PADDLEBOAT_AXIS_BUTTON_DPAD_DOWN 2
#define PADDLEBOAT_AXIS_BUTTON_DPAD_RIGHT 3
#define PADDLEBOAT_AXIS_BUTTON_L2 9
#define PADDLEBOAT_AXIS_BUTTON_R2 12

static const Paddleboat_Controller_Mapping_Data stadia_controller_map[] = {
    16, 0, 0x18d1, 0x9400, PADDLEBOAT_CONTROLLER_LAYOUT_STANDARD,
    {
        /* LX */ AMOTION_EVENT_AXIS_X,
        /* LY */ AMOTION_EVENT_AXIS_Y,
        /* RX */ AMOTION_EVENT_AXIS_Z,
        /* RY */ AMOTION_EVENT_AXIS_RZ,
        /* L1 */ PADDLEBOAT_AXIS_IGNORED,
        /* L2 */ AMOTION_EVENT_AXIS_BRAKE,
        /* R1 */ PADDLEBOAT_AXIS_IGNORED,
        /* R2 */ AMOTION_EVENT_AXIS_GAS,
        /* HX */ AMOTION_EVENT_AXIS_HAT_X,
        /* HY */ AMOTION_EVENT_AXIS_HAT_Y,
    },
    {
        /* LX */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* LY */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* RX */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* RY */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* L1 */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* L2 */ PADDLEBOAT_AXIS_BUTTON_L2,
        /* R1 */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* R2 */ PADDLEBOAT_AXIS_BUTTON_R2,
        /* HX */ PADDLEBOAT_AXIS_BUTTON_DPAD_RIGHT,
        /* HY */ PADDLEBOAT_AXIS_BUTTON_DPAD_DOWN,
    },
    {
        /* LX */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* LY */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* RX */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* RY */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* L1 */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* L2 */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* R1 */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* R2 */ PADDLEBOAT_AXIS_BUTTON_IGNORED,
        /* HX */ PADDLEBOAT_AXIS_BUTTON_DPAD_LEFT,
        /* HY */ PADDLEBOAT_AXIS_BUTTON_DPAD_UP,
    },
    {
        /* UP     */ AKEYCODE_DPAD_UP,
        /* LEFT   */ AKEYCODE_DPAD_LEFT,
        /* DOWN   */ AKEYCODE_DPAD_DOWN,
        /* RIGHT  */ AKEYCODE_DPAD_RIGHT,
        /* A      */ AKEYCODE_BUTTON_A,
        /* B      */ AKEYCODE_BUTTON_B,
        /* X      */ AKEYCODE_BUTTON_X,
        /* Y      */ AKEYCODE_BUTTON_Y,
        /* L1     */ AKEYCODE_BUTTON_L1,
        /* L2     */ AKEYCODE_BUTTON_L2,
        /* L3     */ AKEYCODE_BUTTON_THUMBL,
        /* R1     */ AKEYCODE_BUTTON_R1,
        /* R2     */ AKEYCODE_BUTTON_R2,
        /* R3     */ AKEYCODE_BUTTON_THUMBR,
        /* SELECT */ AKEYCODE_BUTTON_SELECT,
        /* START  */ AKEYCODE_BUTTON_START,
        /* SYSTEM */ AKEYCODE_BUTTON_MODE,
        /* TOUCHP */ PADDLEBOAT_BUTTON_IGNORED,
        /* AUX1   */ PADDLEBOAT_BUTTON_IGNORED,
        /* AUX2   */ PADDLEBOAT_BUTTON_IGNORED,
        /* AUX3   */ PADDLEBOAT_BUTTON_IGNORED,
        /* AUX4   */ PADDLEBOAT_BUTTON_IGNORED
    }
};