Use the Game Controller library

Use the following functions to add game controller support to your game using the Game Controller library.

Initialize and destroy the Game Controller library

Use the Paddleboat_init function to initialize the Game Controller library.

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Paddleboat_init takes two parameters:

Paddleboat_init returns PADDLEBOAT_NO_ERROR if initialization was successful, otherwise an appropriate error code is returned.

You can use Paddleboat_isInitialized to check if the Game Controller library has been successfully initialized. It returns a boolean value. If true, the API is available for use.

bool Paddleboat_isInitialized()

Prior to terminating the application, use the Paddleboat_destroy function to shut down the Game Controller library. The function takes a single parameter, a pointer to a JNIEnv attached to the current thread. Paddleboat_init may be called again after Paddleboat_destroy.

void Paddleboat_destroy(JNIEnv *env)

Inform the library of lifecycle events

The Game Controller library must be informed of activity lifecycle onStop and onStart events. Call the Paddleboat_onStop and Paddleboat_onStart functions from your stop and start event handling code. Both functions take a single parameter: a pointer to a JNIEnv attached to the current thread.

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

Register or remove a controller status callback

The Game Controller library uses a controller status callback to notify a game when a controller is connected or disconnected. It supports only one controller status callback at a time.

  • To register a controller status callback or replace any previously registered callback with a new callback function, call the Paddleboat_setControllerStatusCallback function.
  • To remove any currently registered callback, pass NULL or nullptr.
  • The userData parameter is an optional pointer to user defined data. The userData parameter will be passed to the callback function. This pointer is retained internally until changed by a subsequent call to Paddleboat_setControllerStatusCallback.
void Paddleboat_setControllerStatusCallback(Paddleboat_ControllerStatusCallback
  statusCallback, void *userData)

The function signature of the callback function is:

typedef void (*Paddleboat_ControllerStatusCallback)(
  const int32_t controllerIndex,
  const Paddleboat_ControllerStatus controllerStatus,
  void *userData)
Parameter Description
controllerIndex Index of the controller that initiated the callback. Will be a value between 0 and
PADDLEBOAT_MAX_CONTROLLERS - 1
controllerStatus Enum value of PADDLEBOAT_CONTROLLER_JUST_CONNECTED or
PADDLEBOAT_CONTROLLER_JUST_DISCONNECTED.
userData An optional pointer (may be NULL) to user defined data specified by the last call to Paddleboat_setControllerStatusCallback.

Call the Game Controller library update function

The Game Controller library update function, Paddleboat_update , should be called once per game frame, preferably near the start of the frame. The function takes a single parameter, a pointer to a JNIEnv attached to the current thread.

void Paddleboat_update(JNIEnv *env)

Process events

When receiving input events, your game needs to forward them to the Game Controller library for inspection. The Game Controller library evaluates if an input event is associated with one of its managed devices. Events from managed devices are processed and consumed.

The Game Controller library supports two types of input events: AInputEvents and GameActivity input events.

AInputEvent processing

Your game should forward AInputEvents by calling Paddleboat_processInputEvent from your event handling code.

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

Paddleboat_processInputEvent will return 0 if the event was ignored and 1 if the event was processed and consumed by the Game Controller library.

GameActivity event processing

If your game uses GameActivity, forward GameActivityKeyEvent and GameActivityMotionEvent events by calling Paddleboat_processGameActivityKeyInputEvent or Paddleboat_processGameActivityMotionInputEvent from your event handling code.

int32_t Paddleboat_processGameActivityKeyInputEvent(const void *event,
                                                    const size_t eventSize)
int32_t Paddleboat_processGameActivityMotionInputEvent(const void *event,
                                                       const size_t eventSize)
Parameter Description
event A pointer to a GameActivityKeyEvent or GameActivityMotionEvent structure, depending on which function is being called.
eventSize The size in bytes of the event structure passed in the event parameter.

Both functions will return 0 if the event was ignored and 1 if the event was processed and consumed by the Game Controller library.

GameActivity requires the active motion axis to be specified using the GameActivityPointerAxes_enableAxis function. The Paddleboat_getActiveAxisMask call returns a bitmask of currently active motion axis used by connected controllers.

uint64_t Paddleboat_getActiveAxisMask()

For an example of how to handle this, see the Game Controller library sample that uses GameActivity. The sample polls the active axis mask and informs GameActivity when new axis are used. This is implemented in the NativeEngine::CheckForNewAxis() function.

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;
        }
    }
}

Read controllers

The Game Controller library uses an index value to refer to a specific controller. Valid index values range from 0 to PADDLEBOAT_MAX_CONTROLLERS - 1. The Paddleboat_getControllerStatus function determines the status of a specified controller index.

Paddleboat_ControllerStatus Paddleboat_getControllerStatus(
  const int32_t controllerIndex)

There are three functions for reading information from a connected controller.

Controller name

The Paddleboat_getControllerName function takes two input parameters: a controller index, a buffer size, and a pointer to a buffer to store the controller name string. The name string is formatted as a C string using UTF-8 encoding. The name of the device is obtained internally using InputDevice.getName().

If Paddleboat_getControllerName successfully retrieves the name, it returns PADDLEBOAT_NO_ERROR, otherwise an appropriate error code is returned.

Paddleboat_ErrorCode Paddleboat_getControllerName(const int32_t controllerIndex,
                                                  const size_t bufferSize,
                                                  char *controllerName);
Parameter Description
controllerIndex Index of the controller that initiated the callback. Will be a value between 0 and
PADDLEBOAT_MAX_CONTROLLERS - 1
bufferSize Size in bytes of the buffer passed by controllerName, the name string will be. truncated if necessary to fit in the buffer.
controllerName A pointer to a buffer of bufferSize bytes to store the controller name in. The name will be stored as a C string using UTF-8 encoding.

Controller device information

The Paddleboat_getControllerInfo function takes two input parameters: a controller index and a pointer to a Paddleboat_Controller_Info structure.

If Paddleboat_Controller_Info was successfully populated with data, Paddleboat_getControllerInfo returns PADDLEBOAT_NO_ERROR, otherwise an appropriate error code is returned.

Paddleboat_ErrorCode Paddleboat_getControllerInfo(const int32_t controllerIndex,
  Paddleboat_Controller_Info *controllerInfo)

The Paddleboat_Controller_Info structure contains device-specific information about the controller.

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;

Several struct members are populated by values taken from the InputDevice associated with the controller:

controllerNumber    -   InputDevice.getControllerNumber()
vendorId              - InputDevice.getVendorId()
productId             - InputDevice.getProductId()
deviceId              - InputDevice.getId()
  • A stickFlat value represents the extent of a center flat position. This value is mainly useful for calculating a default center 'dead-zone' on self-centering devices.
  • A stickFuzz value represents the error tolerance, or how far the current value may deviate from the actual value due to noise and device sensitivity limitations.

Both values are normalized to a maximum axis value of 1.0 in either dimension.

The controllerFlags member contains a combination of individual bitmasked flags and multiple-bit combination values.

Performing a logical AND of controllerFlags with PADDLEBOAT_CONTROLLER_LAYOUT_MASK results in a value that may be cast to the Paddleboat_ControllerButtonLayout enum. This enum specifies the button iconography and layout used by the controller.

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
};

The following constants define capability bits. To determine if a controller supports a particular capability, perform a logical AND of the corresponding constant against controllerFlags. A non-zero result means the capability is supported by the controller.

PADDLEBOAT_CONTROLLER_FLAG_TOUCHPAD

If this flag bit is set, the controller has an integrated touchpad. If the touchpad is pressed, the controller sets the PADDLEBOAT_BUTTON_TOUCHPAD bit in the Paddleboat_Controller_Data.buttonsDown field.

PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE

If this flag bit is set, the controller emulates a pointer device. The virtualPointer member of the Paddleboat_Controller_Data structure is populated with the current coordinates of the virtual pointer.

Controller data

The Paddleboat_getControllerData function takes two input parameters: a controller index and a pointer to a Paddleboat_Controller_Data structure. If Paddleboat_Controller_Data is successfully populated with data, Paddleboat_getControllerInfo returns PADDLEBOAT_NO_ERROR, otherwise an appropriate error code is returned.

Paddleboat_ErrorCode Paddleboat_getControllerData(const int32_t controllerIndex,
  Paddleboat_Controller_Data *controllerData)

The Paddleboat_Controller_Data structure contains the current control input values of the controller.

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;

Value ranges

Input type Value range
Thumbstick axis -1.0 to 1.0
Triggers 0.0 to 1.0
Virtual pointers 0.0 to window width/height (in pixels)

Structure details

Structure member Description
buttonsDown Bit-per-button bitfield array. Button bitmask constants are defined in the paddleboat.h. header file and begin with PADDLEBOAT_BUTTON_.
timestamp. Timestamp of the most recent controller input event. The timestamp is microseconds since the clock epoch.
virtualPointer Virtual pointer location. Only valid if the PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE flag is set in controllerFlags, otherwise will be 0.0, 0.0.