Skip to content

Core Interfaces and Data Types

Gamepad<KeysType> is the template base class for all gamepads, responsible for UDP data receiving thread management and callback mechanisms.

Gamepad(int port = kDefaultPort); ///< Specify UDP listening port, default 12121
void StartDataThread(); ///< Start data receiving thread
void StopDataThread(); ///< Stop data receiving thread
KeysType& GetKeys(); ///< Get latest button data (thread-safe)
void SetUpdateCallback(const std::function<void(uint32_t)>& cb); ///< Register data update callback
uint16_t CalculateCrc16(const uint8_t* data, size_t length); ///< CRC-16 checksum calculation

Each time valid data is received and buttons are updated, the SDK calls the registered callback function with the cumulative update count as parameter:

rc.SetUpdateCallback([](uint32_t count) {
// count is the number of valid data updates since startup
});

You can also directly assign the updateCallback_ member:

rc.updateCallback_ = [&](uint32_t count) {
std::cout << "update count: " << count << std::endl;
};

RetroidGamepad inherits Gamepad<RetroidKeys> and is the concrete implementation for the Retroid gamepad.

RetroidGamepad rc(12121); ///< Create Retroid gamepad instance, listening on port 12121
rc.StartDataThread(); ///< Start data receiving
RetroidKeys keys = rc.GetKeys();
std::cout << "A button: " << keys.A << std::endl;
std::cout << "Left axis X: " << keys.left_axis_x << std::endl;

SkydroidGamepad inherits Gamepad<SkydroidKeys> and is the concrete implementation for the Skydroid gamepad.

SkydroidGamepad rc(12121); ///< Create Skydroid gamepad instance, listening on port 12121
rc.StartDataThread(); ///< Start data receiving
SkydroidKeys keys = rc.GetKeys();
std::cout << "A button: " << keys.A << std::endl;
std::cout << "SW1: " << keys.sw1 << std::endl;

UdpReceiver encapsulates the low-level UDP Socket creation, binding, and receiving logic.

UdpReceiver receiver(12121); ///< Create and bind port
std::vector<uint8_t> data = receiver.ReceiveData(); ///< Block and receive one frame of data

ReceiveData() is a blocking call that returns raw bytes when a UDP packet is received.

All data types are defined in gamepad_keys.h.

RetroidKeys — Retroid Gamepad Button Data

Section titled “RetroidKeys — Retroid Gamepad Button Data”
struct RetroidKeys {
double time_stamp; ///< Timestamp (ms, relative to startup time)
union {
uint16_t value; ///< Bitmask of all buttons
struct {
uint8_t R1 : 1;
uint8_t L1 : 1;
uint8_t start : 1;
uint8_t select : 1;
uint8_t R2 : 1;
uint8_t L2 : 1;
uint8_t A : 1;
uint8_t B : 1;
uint8_t X : 1;
uint8_t Y : 1;
uint8_t left : 1;
uint8_t right : 1;
uint8_t up : 1;
uint8_t down : 1;
uint8_t left_axis_button : 1;
uint8_t right_axis_button : 1;
};
};
union {
float axis_values[4];
struct {
float left_axis_x; ///< Left joystick X axis (-1.0 ~ 1.0)
float left_axis_y; ///< Left joystick Y axis (-1.0 ~ 1.0)
float right_axis_x; ///< Right joystick X axis (-1.0 ~ 1.0)
float right_axis_y; ///< Right joystick Y axis (-1.0 ~ 1.0)
};
};
};

SkydroidKeys — Skydroid Gamepad Button Data

Section titled “SkydroidKeys — Skydroid Gamepad Button Data”
struct SkydroidKeys {
double time_stamp; ///< Timestamp (ms, relative to startup time)
union {
uint8_t keys_value;
struct {
uint8_t C : 1;
uint8_t right : 1;
uint8_t D : 1;
uint8_t E : 1;
uint8_t F : 1;
uint8_t reserved : 1;
uint8_t A : 1;
uint8_t B : 1;
};
};
union {
uint8_t switch_keys[4];
struct {
uint8_t sw1; ///< Toggle switch 1
uint8_t sw2; ///< Toggle switch 2
uint8_t sw3; ///< Toggle switch 3
uint8_t sw4; ///< Toggle switch 4
};
};
union {
float axis_values[4];
struct {
float left_axis_x; ///< Left joystick X axis (-1.0 ~ 1.0)
float left_axis_y; ///< Left joystick Y axis (-1.0 ~ 1.0)
float right_axis_x; ///< Right joystick X axis (-1.0 ~ 1.0)
float right_axis_y; ///< Right joystick Y axis (-1.0 ~ 1.0)
};
};
};
ValueMeaning
0Button released (KeyStatus::kReleased)
1Button pressed (KeyStatus::kPressed)

Raw joystick data ranges from -1000 ~ 1000. The SDK divides by kJoystickRange (1000) internally to normalize to -1.0 ~ 1.0 floating-point values.

DirectionMinimumMaximum
X axis-1.0 (far left)1.0 (far right)
Y axis-1.0 (far bottom)1.0 (far top)
ButtonDescription
A / B / X / YFour action buttons
L1 / R1Left/right shoulder buttons
L2 / R2Left/right trigger buttons
start / selectStart/select buttons
up / down / left / rightDirectional pad
left_axis_button / right_axis_buttonLeft/right joystick press
ButtonDescription
A / B / C / D / E / FAction buttons
rightDirectional pad (right)
sw1 / sw2 / sw3 / sw4Four toggle switches
struct RetroidGamepadData {
uint8_t stx[2]; ///< Frame header 0x55 0x66
uint8_t ctrl; ///< Control byte
uint16_t data_len; ///< Data area length
uint16_t seq; ///< Sequence number
uint8_t id; ///< Device ID (1 = Retroid)
uint16_t crc16; ///< CRC-16 checksum
union {
uint8_t data[32]; ///< Raw data area
struct {
uint16_t buttons[10]; ///< 10 button channels
int16_t left_axis_x; ///< Left joystick X
int16_t left_axis_y; ///< Left joystick Y
int16_t right_axis_x; ///< Right joystick X
int16_t right_axis_y; ///< Right joystick Y
uint16_t axis_buttons[2]; ///< Joystick buttons
};
};
};
struct SkydroidGamepadData {
uint8_t stx[2]; ///< Frame header 0x55 0x66
uint8_t ctrl; ///< Control byte
uint16_t data_len; ///< Data area length
uint16_t seq; ///< Sequence number
uint8_t id; ///< Device ID (2 = Skydroid)
uint16_t crc16; ///< CRC-16 checksum
union {
uint8_t data[32]; ///< Raw data area
struct {
int16_t right_axis_x; ///< Right joystick X
int16_t right_axis_y; ///< Right joystick Y
int16_t left_axis_y; ///< Left joystick Y
int16_t left_axis_x; ///< Left joystick X
uint16_t switch_keys[4]; ///< 4 toggle switches
uint16_t buttons[8]; ///< 8 button channels
};
};
};

Note: The joystick data ordering in the protocol frame differs between the two gamepads. The SDK handles the mapping automatically.