cOMS/Input/XInput.h
Dennis Eichhorn 4ed50a08bc
Some checks failed
CI / code-tests: ${{ matrix.os }} / ${{ matrix.platform }} (ubuntu-latest, x64) (push) Has been cancelled
CI / code-tests: ${{ matrix.os }} / ${{ matrix.platform }} (ubuntu-latest, x86) (push) Has been cancelled
CI / general_module_workflow_c (push) Has been cancelled
update
2024-06-08 13:49:05 +02:00

175 lines
6.0 KiB
C++

/**
* Karaka
*
* @package Stdlib
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://jingga.app
*/
#ifndef INPUT_XINPUT_H
#define INPUT_XINPUT_H
#ifdef _WIN32
#include <XInput.h>
#include <windows.h>
#else
#include <linux/joystick.h>
#endif
#include "../Stdlib/Types.h"
#include "../Utils/MathUtils.h"
#define MIN_CONTROLLER_DEVICES 4
namespace Input {
struct ControllerState {
uint32 id = 0;
bool is_connected = false;
// After handling the state change the game loop should set this to false
bool state_change = false;
bool up = false;
bool down = false;
bool left = false;
bool right = false;
bool start = false;
bool back = false;
bool shoulder_left = false;
bool shoulder_right = false;
byte trigger_left = 0;
byte trigger_right = 0;
bool button_a = false;
bool button_b = false;
bool button_x = false;
bool button_y = false;
int16 stickl_x = 0;
int16 stickl_y = 0;
bool stickl_press = false;
int16 stickr_x = 0;
int16 stickr_y = 0;
bool stickr_press = false;
};
// @todo consider to remove some global_persist and defines since we are never calling it somewhere else
// BEGIN: Dynamically load XInput
typedef DWORD WINAPI x_input_get_state(DWORD, XINPUT_STATE*);
DWORD WINAPI XInputGetStateStub(DWORD, XINPUT_STATE*) {
return 0;
}
global_persist x_input_get_state* XInputGetState_ = XInputGetStateStub;
#define XInputGetState XInputGetState_
typedef DWORD WINAPI x_input_set_state(DWORD, XINPUT_VIBRATION*);
DWORD WINAPI XInputSetStateStub(DWORD, XINPUT_VIBRATION*) {
return 0;
}
global_persist x_input_set_state* XInputSetState_ = XInputSetStateStub;
#define XInputSetState XInputSetState_
void xinput_load() {
HMODULE lib = LoadLibraryExA((LPCSTR) "xinput1_4.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if(!lib) {
// @todo Log
lib = LoadLibraryExA((LPCSTR) "xinput1_3.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (!lib) {
// @todo Log
return;
}
XInputGetState = (x_input_get_state *) GetProcAddress(lib, "XInputGetState");
XInputSetState = (x_input_set_state *) GetProcAddress(lib, "XInputSetState");
if (!XInputGetState || !XInputSetState) {
// @todo Log
return;
}
}
// END: Dynamically load XInput
ControllerState* init_controllers()
{
uint32 c = 0;
for (uint32 controller_index = 0; controller_index < XUSER_MAX_COUNT; ++controller_index) {
XINPUT_STATE controller_state;
if (XInputGetState(controller_index, &controller_state) == ERROR_SUCCESS) {
++c;
}
}
c = OMS_MAX(MIN_CONTROLLER_DEVICES, c);
// We always want at least one empty controller slot
// @todo Change so that we store the actual number of devices
ControllerState *controllers = (ControllerState *) calloc((c + 1), sizeof(ControllerState));
if (c == 0) {
return controllers;
}
c = 0;
for (uint32 controller_index = 0; controller_index < XUSER_MAX_COUNT; ++controller_index) {
XINPUT_STATE controller_state;
if (XInputGetState(controller_index, &controller_state) == ERROR_SUCCESS) {
++c;
controllers[c].id = controller_index;
controllers[c].is_connected = true;
}
}
return controllers;
}
void handle_controller_input(ControllerState* states)
{
uint32 controller_index = 0;
while(states[controller_index].is_connected) {
XINPUT_STATE controller_state;
if (XInputGetState(controller_index, &controller_state) != ERROR_SUCCESS) {
++controller_index;
continue;
}
states[controller_index].up = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
states[controller_index].down = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
states[controller_index].left = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
states[controller_index].right = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
states[controller_index].start = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_START;
states[controller_index].back = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK;
states[controller_index].shoulder_left = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
states[controller_index].shoulder_right = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;
states[controller_index].trigger_left = controller_state.Gamepad.bLeftTrigger;
states[controller_index].trigger_right = controller_state.Gamepad.bRightTrigger;
states[controller_index].button_a = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_A;
states[controller_index].button_b = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_B;
states[controller_index].button_x = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_X;
states[controller_index].button_y = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_Y;
states[controller_index].stickl_x = controller_state.Gamepad.sThumbLX;
states[controller_index].stickl_y = controller_state.Gamepad.sThumbLY;
states[controller_index].stickl_press = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB;
states[controller_index].stickr_x = controller_state.Gamepad.sThumbRX;
states[controller_index].stickr_y = controller_state.Gamepad.sThumbRY;
states[controller_index].stickr_press = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB;
++controller_index;
}
}
}
#endif