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:
- A pointer to a
JNIEnv
attached to the current thread - A
jobject
JNI object reference to aContext
derived class. AnyContext
derived class object is valid, including but not limited toActivity
,NativeActivity
, orGameActivity
.
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
ornullptr
. - The
userData
parameter is an optional pointer to user defined data. TheuserData
parameter will be passed to the callback function. This pointer is retained internally until changed by a subsequent call toPaddleboat_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.
- The
Paddleboat_getControllerName
function retrieves the name of the controller device. - The
Paddleboat_getControllerInfo
function retrieves data about the controller device itself. - The
Paddleboat_getControllerData
function retrieves the current state of the controller inputs.
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 . |