Usar a biblioteca Game Controller

Use as funções a seguir para adicionar compatibilidade com o controle de jogo usando a biblioteca Game Controller.

Inicializar e destruir a biblioteca Game Controller

Use a função Paddleboat_init para inicializar a biblioteca Game Controller.

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Paddleboat_init requer dois parâmetros:

  • Um ponteiro para um JNIEnv anexado à linha de execução atual
  • Uma referência de objeto JNI jobject a uma classe derivada de Context. Qualquer Context objeto de classe derivado é válido, incluindo, mas não se limitando a Activity, NativeActivity, ou GameActivity.

Paddleboat_init retornará PADDLEBOAT_NO_ERROR se a inicialização tiver êxito. Caso contrário, um código de erro adequado será retornado.

Você pode usar Paddleboat_isInitialized para verificar se a biblioteca Game Controller foi inicializada. Ele retorna um valor booleano. Se for verdadeiro, a API estará disponível para uso.

bool Paddleboat_isInitialized()

Antes de encerrar o aplicativo, use a função Paddleboat_destroy para encerrar a biblioteca Game Controller. A função usa um único parâmetro, um ponteiro para um JNIEnv anexado à linha de execução atual. Paddleboat_init pode ser chamado novamente após Paddleboat_destroy.

void Paddleboat_destroy(JNIEnv *env)

Informar a biblioteca de eventos de ciclo de vida

A biblioteca Game Controller precisa ser informada dos eventos de ciclo de vida da atividade onStop e onStart. Chame as funções Paddleboat_onStop e Paddleboat_onStart do seu código de processamento de eventos de parada e início. As duas funções têm um único parâmetro: um ponteiro para um JNIEnv anexado à linha de execução atual.

void Paddleboat_onStop(JNIEnv *env)
void Paddleboat_onStart(JNIEnv *env)

Registrar ou remover um callback de status do controle

A biblioteca Game Controller usa um callback de status do controle para notificar um jogo quando um controle está conectado ou desconectado. Ela é compatível apenas com um callback de status de controle por vez.

  • Para registrar um callback de status de controle ou substituir qualquer outro registrado anteriormente por uma nova função de callback, chame a função Paddleboat_setControllerStatusCallback.
  • Para remover qualquer callback registrado no momento, transmita NULL ou nullptr.
  • O parâmetro userData é um ponteiro opcional para dados definidos pelo usuário. A O parâmetro userData será transmitido para a função de callback. Esse ponteiro é mantido internamente até que seja alterado por uma chamada subsequente para Paddleboat_setControllerStatusCallback.
void Paddleboat_setControllerStatusCallback(Paddleboat_ControllerStatusCallback
  statusCallback, void *userData)

A assinatura da função de callback é:

typedef void (*Paddleboat_ControllerStatusCallback)(
  const int32_t controllerIndex,
  const Paddleboat_ControllerStatus controllerStatus,
  void *userData)
Parâmetro Descrição
controllerIndex O índice do controle que iniciou o callback. Será um valor entre 0 e
PADDLEBOAT_MAX_CONTROLLERS - 1
controllerStatus Valor de enumeração de PADDLEBOAT_CONTROLLER_JUST_CONNECTED ou
PADDLEBOAT_CONTROLLER_JUST_DISCONNECTED.
userData Um ponteiro opcional (pode ser NULL) para dados definidos pelo usuário especificados pela última chamada para Paddleboat_setControllerStatusCallback.

Chamar a função de atualização da biblioteca Game Controller

A função de atualização da biblioteca Game Controller, Paddleboat_update, precisa ser chamada uma vez por frame do jogo, de preferência perto do início do frame. A função usa um único parâmetro, um ponteiro para um JNIEnv anexado ao linha de execução atual.

void Paddleboat_update(JNIEnv *env)

Processar eventos

Ao receber eventos de entrada, seu jogo precisa encaminhá-los à biblioteca Game Controller para inspeção. Essa biblioteca avalia se um evento de entrada está associado a um dos dispositivos gerenciados. Os eventos de dispositivos gerenciados são processados e consumidos.

A biblioteca Game Controller é compatível com dois tipos de eventos de entrada: AInputEvents e GameActivity.

Processamento de AInputEvent

Seu jogo precisa encaminhar AInputEvents chamando Paddleboat_processInputEvent do código de processamento de eventos.

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

Paddleboat_processInputEvent retornará 0 se o evento for ignorado e 1 se ele tiver sido processado e consumido pela biblioteca Game Controller.

Processamento de eventos de GameActivity

Caso seu jogo use GameActivity, encaminhe GameActivityKeyEvent e GameActivityMotionEvent de eventos chamando Paddleboat_processGameActivityKeyInputEvent ou Paddleboat_processGameActivityMotionInputEvent do código de manipulação de eventos.

int32_t Paddleboat_processGameActivityKeyInputEvent(const void *event,
                                                    const size_t eventSize)
int32_t Paddleboat_processGameActivityMotionInputEvent(const void *event,
                                                       const size_t eventSize)
Parâmetro Descrição
event Um ponteiro para uma estrutura GameActivityKeyEvent ou GameActivityMotionEvent, dependendo de qual função está sendo chamada.
eventSize O tamanho em bytes da estrutura do evento transmitido no parâmetro event.

Ambas as funções retornarão 0 se o evento tiver sido ignorado e 1 se tiver sido processado e consumido pela biblioteca Game Controller.

GameActivity requer que o eixo de movimento ativo seja especificado usando a função GameActivityPointerAxes_enableAxis. A chamada Paddleboat_getActiveAxisMask retorna um bitmask do eixo de movimento ativo atualmente usado pelos controles conectados.

uint64_t Paddleboat_getActiveAxisMask()

Para ver um exemplo de como lidar com isso, consulte o exemplo da biblioteca Game Controller que usa GameActivity. A amostra pesquisa a máscara do eixo ativo e informa GameActivity quando um novo eixo é usado. Isso é implementado na função NativeEngine::CheckForNewAxis().

void NativeEngine::CheckForNewAxis() {
    // Tell GameActivity about any new axis ids so it reports
    // their events
    const uint64_t activeAxisIds = Paddleboat_getActiveAxisMask();
    uint64_t newAxisIds = activeAxisIds ^ mActiveAxisIds;
    if (newAxisIds != 0) {
        mActiveAxisIds = activeAxisIds;
        int32_t currentAxisId = 0;
        while(newAxisIds != 0) {
            if ((newAxisIds & 1) != 0) {
                LOGD("Enable Axis: %d", currentAxisId);
                GameActivityPointerAxes_enableAxis(currentAxisId);
            }
            ++currentAxisId;
            newAxisIds >>= 1;
        }
    }
}

Ler controles

A biblioteca Game Controller usa um valor de índice para se referir a um controle específico. Os valores de índice válidos variam de 0 a PADDLEBOAT_MAX_CONTROLLERS - 1. A Paddleboat_getControllerStatus determina o status de um índice de controle especificado.

Paddleboat_ControllerStatus Paddleboat_getControllerStatus(
  const int32_t controllerIndex)

Há três funções para ler informações de um controle conectado.

Nome do controle

A Paddleboat_getControllerName function usa dois parâmetros de entrada: um índice de controle, um tamanho de buffer e um ponteiro para um buffer para armazenar a string de nome do controle. A string de nome é formatada como uma string C usando a codificação UTF-8. O nome do dispositivo é coletado internamente usando InputDevice.getName().

Se Paddleboat_getControllerName recuperar o nome, retornará PADDLEBOAT_NO_ERROR. Caso contrário, um código de erro adequado será retornado.

Paddleboat_ErrorCode Paddleboat_getControllerName(const int32_t controllerIndex,
                                                  const size_t bufferSize,
                                                  char *controllerName);
Parâmetro Descrição
controllerIndex O índice do controle que iniciou o callback. Será um valor entre 0 e
PADDLEBOAT_MAX_CONTROLLERS - 1
bufferSize Tamanho em bytes do buffer passado por controllerName. A string do nome será truncada, se necessário, para caber no buffer.
controllerName Um ponteiro para um buffer de bufferSize bytes para armazenar o nome do controle. O nome será armazenado como uma string C usando a codificação UTF-8.

Informações do controle

A Paddleboat_getControllerInfo function utiliza dois parâmetros de entrada: um índice do controle e um ponteiro para uma estrutura Paddleboat_Controller_Info.

Se Paddleboat_Controller_Info tiver sido preenchido com os dados, Paddleboat_getControllerInfo retornará PADDLEBOAT_NO_ERROR. Caso contrário, será retornado um código de erro apropriado.

Paddleboat_ErrorCode Paddleboat_getControllerInfo(const int32_t controllerIndex,
  Paddleboat_Controller_Info *controllerInfo)

A estrutura Paddleboat_Controller_Info contém informações específicas sobre o controle.

typedef struct Paddleboat_Controller_Info {
    uint32_t controllerFlags;
    int32_t controllerNumber;
    int32_t vendorId;
    int32_t productId;
    int32_t deviceId;
    Paddleboat_Controller_Thumbstick_Precision leftStickPrecision;
    Paddleboat_Controller_Thumbstick_Precision rightStickPrecision;
} Paddleboat_Controller_Info;

typedef struct Paddleboat_Controller_Thumbstick_Precision {
    float stickFlatX;
    float stickFlatY;
    float stickFuzzX;
    float stickFuzzY;
} Paddleboat_Controller_Thumbstick_Precision;

Vários membros da estrutura são preenchidos por valores retirados do InputDevice associado ao controle:

controllerNumber    -   InputDevice.getControllerNumber()
vendorId              - InputDevice.getVendorId()
productId             - InputDevice.getProductId()
deviceId              - InputDevice.getId()
  • Um valor stickFlat representa a extensão de uma posição central. Esse valor é útil principalmente para calcular uma "zona inativa" padrão em dispositivos de autocentralização.
  • Um valor stickFuzz representa a tolerância a erros ou o quanto o valor atual pode ser diferente do valor real devido a limitações de ruído e sensibilidade do dispositivo.

Ambos os valores são normalizados para um valor máximo de eixo de 1.0 em qualquer dimensão.

O membro controllerFlags contém uma combinação de sinalizações com bitmasks individuais e valores de combinação de vários bits.

A execução de um AND lógico de controllerFlags com PADDLEBOAT_CONTROLLER_LAYOUT_MASK resulta em um valor que pode ser transmitido para a enumeração Paddleboat_ControllerButtonLayout. Essa enumeração especifica a iconografia e o layout dos botões usados pelo controle.

enum Paddleboat_ControllerButtonLayout {
    //  Y
    // X B
    //  A
    PADDLEBOAT_CONTROLLER_LAYOUT_STANDARD = 0,
    //  △
    // □ ○
    //  x
    PADDLEBOAT_CONTROLLER_LAYOUT_SHAPES = 1,
    //  X
    // Y A
    //  B
    PADDLEBOAT_CONTROLLER_LAYOUT_REVERSE = 2,
    // X Y R1 L1
    // A B R2 L2
    PADDLEBOAT_CONTROLLER_LAYOUT_ARCADE_STICK = 3,
    PADDLEBOAT_CONTROLLER_LAYOUT_MASK = 3
};

As constantes a seguir definem bits de capacidade. Para determinar se um controle é compatível com uma capacidade específica, execute um AND lógico da constante correspondente em relação a controllerFlags. Um resultado diferente de zero significa que o recurso é compatível com o controle.

PADDLEBOAT_CONTROLLER_FLAG_TOUCHPAD

Se esse bit de sinalização estiver definido, o controle trá um touchpad integrado. Se o touchpad for pressionado, o controle definirá o bit PADDLEBOAT_BUTTON_TOUCHPAD no campo Paddleboat_Controller_Data.buttonsDown.

PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE

Se esse bit de sinalização estiver definido, o controle emulará um dispositivo apontador. O membro virtualPointer da estrutura Paddleboat_Controller_Data é preenchido com as coordenadas atuais do ponteiro virtual.

Dados do controle

A função Paddleboat_getControllerData usa dois parâmetros de entrada: um índice de controle e um ponteiro para uma estrutura Paddleboat_Controller_Data. Se Paddleboat_Controller_Data foi preenchido com os dados. Paddleboat_getControllerInfo retorna PADDLEBOAT_NO_ERROR. Caso contrário, um o código de erro apropriado será retornado.

Paddleboat_ErrorCode Paddleboat_getControllerData(const int32_t controllerIndex,
  Paddleboat_Controller_Data *controllerData)

A estrutura Paddleboat_Controller_Data contém os valores de entrada atuais do controle.

typedef struct Paddleboat_Controller_Data {
    uint64_t timestamp;
    uint32_t buttonsDown;
    Paddleboat_Controller_Thumbstick leftStick;
    Paddleboat_Controller_Thumbstick rightStick;
    float triggerL1;
    float triggerL2;
    float triggerR1;
    float triggerR2;
    Paddleboat_Controller_Pointer virtualPointer;
} Paddleboat_Controller_Data;

typedef struct Paddleboat_Controller_Pointer {
    float pointerX;
    float pointerY;
} Paddleboat_Controller_Pointer;

typedef struct Paddleboat_Controller_Thumbstick {
    float stickX;
    float stickY;
} Paddleboat_Controller_Thumbstick;

Intervalos de valor

Tipo de entrada Intervalo de valor
Eixo do controle direcional analógico de -1.0 a 1.0
Gatilhos de 0.0 a 1.0
Ponteiros virtuais 0.0 à largura/altura da janela (em pixels)

Detalhes da estrutura

Membro da estrutura Descrição
buttonsDown Matriz de bitfield em bits por botão. As constantes de bitmask do botão são definidas no arquivo de cabeçalho paddleboat.h e começam com PADDLEBOAT_BUTTON_.
timestamp. O carimbo de data/hora do evento mais recente de entrada do controle. O carimbo de data/hora é exibido em microssegundos desde a época do relógio.
virtualPointer Localização do ponteiro virtual. Válido apenas se a sinalização PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE estiver definida em controllerFlags. Caso contrário, será 0.0, 0.0.