controller as mouse

This commit is contained in:
EqUiNoX
2025-10-11 22:11:54 -06:00
parent f6e7ffb948
commit d08d6fb00a
4 changed files with 231 additions and 24 deletions
+171 -22
View File
@@ -1,13 +1,18 @@
#include "input_manager.h"
#include "graphics.h"
#include "math.h"
#include "debug.h"
namespace
{
bool mInitialized = false;
HANDLE mControllerHandles[XGetPortCount()];
DWORD mControllerLastPacketNumber[XGetPortCount()];
ControllerState mControllerStatesCurrent[XGetPortCount()];
ControllerState mControllerStatesPrevious[XGetPortCount()];
HANDLE mMouseHandles[XGetPortCount()];
XINPUT_STATE mMouseInputStates[XGetPortCount()];
DWORD mMouseLastPacketNumber[XGetPortCount()];
MouseState mMouseStatesCurrent[XGetPortCount()];
MouseState mMouseStatesPrevious[XGetPortCount()];
@@ -20,8 +25,12 @@ void input_manager::init()
{
XInitDevices(0, 0);
memset(mControllerHandles, 0, sizeof(mControllerHandles));
memset(mControllerLastPacketNumber, 0, sizeof(mControllerLastPacketNumber));
memset(mControllerStatesCurrent, 0, sizeof(mControllerStatesCurrent));
memset(mControllerStatesPrevious, 0, sizeof(mControllerStatesPrevious));
memset(mMouseHandles, 0, sizeof(mMouseHandles));
memset(mMouseInputStates, 0, sizeof(mMouseInputStates));
memset(mMouseLastPacketNumber, 0, sizeof(mMouseLastPacketNumber));
memset(mMouseStatesCurrent, 0, sizeof(mMouseStatesCurrent));
memset(mMouseStatesPrevious, 0, sizeof(mMouseStatesPrevious));
@@ -37,6 +46,100 @@ void input_manager::init()
XInputDebugInitKeyboardQueue(&keyboardSettings);
}
void input_manager::process_controller()
{
DWORD insertions = 0;
DWORD removals = 0;
if (XGetDeviceChanges(XDEVICE_TYPE_GAMEPAD, &insertions, &removals) == TRUE)
{
for (int i = 0; i < XGetPortCount(); i++)
{
if ((insertions & 1) == 1)
{
mControllerHandles[i] = XInputOpen(XDEVICE_TYPE_GAMEPAD, i, XDEVICE_NO_SLOT, NULL);
}
if ((removals & 1) == 1)
{
XInputClose(mControllerHandles[i]);
mControllerHandles[i] = NULL;
}
insertions = insertions >> 1;
removals = removals >> 1;
}
}
for (int i = 0; i < XGetPortCount(); i++)
{
XINPUT_STATE controllerInputState;
if (mControllerHandles[i] == NULL || XInputGetState(mControllerHandles[i], &controllerInputState) != 0)
{
continue;
}
if (mControllerLastPacketNumber[i] != controllerInputState.dwPacketNumber)
{
memcpy(&mControllerStatesPrevious[i], &mControllerStatesCurrent[i], sizeof(ControllerState));
mControllerStatesCurrent[i].buttons[CONTROLLER_A_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_A] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_B_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_B] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_X_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_X] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_Y_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_Y] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_BLACK_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_BLACK] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_WHITE_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_WHITE] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_LTRIGGER_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_RTRIGGER_BUTTON] = controllerInputState.Gamepad.bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER] > 32;
mControllerStatesCurrent[i].buttons[CONTROLLER_DPAD_UP_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_DPAD_DOWN_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_DPAD_LEFT_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_DPAD_RIGHT_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_START_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_BACK_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_LTHUMB_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0;
mControllerStatesCurrent[i].buttons[CONTROLLER_RTHUMB_BUTTON] = (controllerInputState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0;
const float sensitivity = 10.0f;
const float acceleration = 1.6f;
const float friction = 0.85f;
const float maxSpeed = 15.0f;
const float deadzone = 0.25f;
float lx = controllerInputState.Gamepad.sThumbLX / 32768.0f;
float ly = -(controllerInputState.Gamepad.sThumbLY / 32768.0f);
float rx = controllerInputState.Gamepad.sThumbRX / 32768.0f;
float ry = -(controllerInputState.Gamepad.sThumbRY / 32768.0f);
lx = fabsf(lx) < deadzone ? 0 : (lx - math::copy_sign(deadzone, lx)) / (1.0f - deadzone);
ly = fabsf(ly) < deadzone ? 0 : (ly - math::copy_sign(deadzone, ly)) / (1.0f - deadzone);
rx = fabsf(rx) < deadzone ? 0 : (rx - math::copy_sign(deadzone, rx)) / (1.0f - deadzone);
ry = fabsf(ry) < deadzone ? 0 : (ry - math::copy_sign(deadzone, ry)) / (1.0f - deadzone);
mControllerStatesCurrent[i].velocity_left_x = (mControllerStatesPrevious[i].velocity_left_x + lx * acceleration) * friction;
mControllerStatesCurrent[i].velocity_left_y = (mControllerStatesPrevious[i].velocity_left_y + ly * acceleration) * friction;
mControllerStatesCurrent[i].velocity_left_x = math::clamp_float(mControllerStatesCurrent[i].velocity_left_x, -maxSpeed, maxSpeed);
mControllerStatesCurrent[i].velocity_left_y = math::clamp_float(mControllerStatesCurrent[i].velocity_left_y, -maxSpeed, maxSpeed);
mControllerStatesCurrent[i].velocity_right_x = (mControllerStatesPrevious[i].velocity_right_x + lx * acceleration) * friction;
mControllerStatesCurrent[i].velocity_right_y = (mControllerStatesPrevious[i].velocity_right_y + ly * acceleration) * friction;
mControllerStatesCurrent[i].velocity_right_x = math::clamp_float(mControllerStatesCurrent[i].velocity_right_x, -maxSpeed, maxSpeed);
mControllerStatesCurrent[i].velocity_right_y = math::clamp_float(mControllerStatesCurrent[i].velocity_right_y, -maxSpeed, maxSpeed);
lx = lx * sensitivity;
ly = ly * sensitivity;
rx = rx * sensitivity;
ry = ry * sensitivity;
mControllerStatesCurrent[i].thumb_left_dx = (int)lx;
mControllerStatesCurrent[i].thumb_left_dy = (int)ly;
mControllerStatesCurrent[i].thumb_right_dx = (int)rx;
mControllerStatesCurrent[i].thumb_right_dy = (int)ry;
mControllerStatesCurrent[i].thumb_left_x = math::clamp_int((int)(mControllerStatesPrevious[i].thumb_left_x + lx), 0, graphics::getWidth());
mControllerStatesCurrent[i].thumb_left_y = math::clamp_int((int)(mControllerStatesPrevious[i].thumb_left_y + ly), 0, graphics::getHeight());
mControllerStatesCurrent[i].thumb_right_x = math::clamp_int((int)(mControllerStatesPrevious[i].thumb_right_x + rx), 0, graphics::getWidth());
mControllerStatesCurrent[i].thumb_right_y = math::clamp_int((int)(mControllerStatesPrevious[i].thumb_right_y + ry), 0, graphics::getHeight());
mControllerLastPacketNumber[i] = controllerInputState.dwPacketNumber;
}
}
}
void input_manager::process_mouse()
{
DWORD insertions = 0;
@@ -61,25 +164,26 @@ void input_manager::process_mouse()
for (int i = 0; i < XGetPortCount(); i++)
{
if (mMouseHandles[i] == NULL || XInputGetState(mMouseHandles[i], &mMouseInputStates[i]) != 0)
XINPUT_STATE mouseInputState;
if (mMouseHandles[i] == NULL || XInputGetState(mMouseHandles[i], &mouseInputState) != 0)
{
continue;
}
if (mMouseLastPacketNumber[i] != mMouseInputStates[i].dwPacketNumber)
if (mMouseLastPacketNumber[i] != mouseInputState.dwPacketNumber)
{
memcpy(&mMouseStatesPrevious[i], &mMouseStatesCurrent[i], sizeof(MouseState));
mMouseStatesCurrent[i].dx = mMouseInputStates[i].DebugMouse.cMickeysX;
mMouseStatesCurrent[i].dy = mMouseInputStates[i].DebugMouse.cMickeysY;
memcpy(&mMouseStatesPrevious[i], &mouseInputState, sizeof(MouseState));
mMouseStatesCurrent[i].dx = mouseInputState.DebugMouse.cMickeysX;
mMouseStatesCurrent[i].dy = mouseInputState.DebugMouse.cMickeysY;
mMouseStatesCurrent[i].dz = mouseInputState.DebugMouse.cWheel;
mMouseStatesCurrent[i].x = math::clamp_int(mMouseStatesPrevious[i].x + mMouseStatesCurrent[i].dx, 0, graphics::getWidth());
mMouseStatesCurrent[i].y = math::clamp_int(mMouseStatesPrevious[i].y + mMouseStatesCurrent[i].dy, 0, graphics::getHeight());
mMouseStatesCurrent[i].dz = mMouseInputStates[i].DebugMouse.cWheel;
mMouseStatesCurrent[i].button[MOUSE_LEFT_BUTTON] = (mMouseInputStates[i].DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_LEFT_BUTTON) != 0;
mMouseStatesCurrent[i].button[MOUSE_RIGHT_BUTTON] = (mMouseInputStates[i].DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_RIGHT_BUTTON) != 0;
mMouseStatesCurrent[i].button[MOUSE_MIDDLE_BUTTON] = (mMouseInputStates[i].DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_MIDDLE_BUTTON) != 0;
mMouseStatesCurrent[i].button[MOUSE_EXTRA_BUTTON1] = (mMouseInputStates[i].DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_XBUTTON1) != 0;
mMouseStatesCurrent[i].button[MOUSE_EXTRA_BUTTON2] = (mMouseInputStates[i].DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_XBUTTON2) != 0;
mMouseLastPacketNumber[i] = mMouseInputStates[i].dwPacketNumber;
mMouseStatesCurrent[i].buttons[MOUSE_LEFT_BUTTON] = (mouseInputState.DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_LEFT_BUTTON) != 0;
mMouseStatesCurrent[i].buttons[MOUSE_RIGHT_BUTTON] = (mouseInputState.DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_RIGHT_BUTTON) != 0;
mMouseStatesCurrent[i].buttons[MOUSE_MIDDLE_BUTTON] = (mouseInputState.DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_MIDDLE_BUTTON) != 0;
mMouseStatesCurrent[i].buttons[MOUSE_EXTRA_BUTTON1] = (mouseInputState.DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_XBUTTON1) != 0;
mMouseStatesCurrent[i].buttons[MOUSE_EXTRA_BUTTON2] = (mouseInputState.DebugMouse.bButtons & XINPUT_DEBUG_MOUSE_XBUTTON2) != 0;
mMouseLastPacketNumber[i] = mouseInputState.dwPacketNumber;
}
}
}
@@ -136,6 +240,22 @@ void input_manager::process_keyboard()
}
}
bool input_manager::controller_pressed(CONTROLLER_BUTTON button, int port)
{
for (int i = 0; i < XGetPortCount(); i++)
{
if (port >= 0 && port != i || mControllerHandles[i] == NULL)
{
continue;
}
if (mControllerStatesCurrent[i].buttons[button] == true && mControllerStatesPrevious[i].buttons[button] == false)
{
return true;
}
}
return false;
}
bool input_manager::mouse_pressed(MOUSE_BUTTON button, int port)
{
for (int i = 0; i < XGetPortCount(); i++)
@@ -144,7 +264,7 @@ bool input_manager::mouse_pressed(MOUSE_BUTTON button, int port)
{
continue;
}
if (mMouseStatesCurrent[i].button[button] == true && mMouseStatesPrevious[i].button[button] == false)
if (mMouseStatesCurrent[i].buttons[button] == true && mMouseStatesPrevious[i].buttons[button] == false)
{
return true;
}
@@ -152,6 +272,23 @@ bool input_manager::mouse_pressed(MOUSE_BUTTON button, int port)
return false;
}
bool input_manager::try_get_controller_state(int port, ControllerState* controllerState)
{
if (controllerState != NULL)
{
for (int i = 0; i < XGetPortCount(); i++)
{
if (port >= 0 && port != i || mControllerHandles[i] == NULL)
{
continue;
}
*controllerState = mControllerStatesCurrent[i];
return true;
}
}
return false;
}
bool input_manager::try_get_mouse_state(int port, MouseState* mouseState)
{
if (mouseState != NULL)
@@ -201,6 +338,7 @@ bool input_manager::try_get_keyboard_state(int port, KeyboardState* keyboardStat
void input_manager::pump_input(nk_context *context)
{
process_controller();
process_mouse();
process_keyboard();
@@ -238,14 +376,25 @@ void input_manager::pump_input(nk_context *context)
}
}
MouseState mouseState;
memset(&mouseState, 0, sizeof(mouseState));
if (try_get_mouse_state(-1, &mouseState))
//MouseState mouseState;
//memset(&mouseState, 0, sizeof(mouseState));
//if (try_get_mouse_state(-1, &mouseState))
//{
// nk_input_motion(context, mouseState.x, mouseState.y);
// nk_input_button(context, NK_BUTTON_LEFT, mouseState.x, mouseState.y, mouseState.buttons[MOUSE_LEFT_BUTTON]);
// nk_input_button(context, NK_BUTTON_MIDDLE, mouseState.x, mouseState.y, mouseState.buttons[MOUSE_MIDDLE_BUTTON]);
// nk_input_button(context, NK_BUTTON_RIGHT, mouseState.x, mouseState.y, mouseState.buttons[MOUSE_RIGHT_BUTTON]);
//}
ControllerState controllerState;
memset(&controllerState, 0, sizeof(controllerState));
if (try_get_controller_state(-1, &controllerState))
{
nk_input_motion(context, mouseState.x, mouseState.y);
nk_input_button(context, NK_BUTTON_LEFT, mouseState.x, mouseState.y, mouseState.button[MOUSE_LEFT_BUTTON]);
nk_input_button(context, NK_BUTTON_MIDDLE, mouseState.x, mouseState.y, mouseState.button[MOUSE_MIDDLE_BUTTON]);
nk_input_button(context, NK_BUTTON_RIGHT, mouseState.x, mouseState.y, mouseState.button[MOUSE_RIGHT_BUTTON]);
nk_input_motion(context, controllerState.thumb_left_x, controllerState.thumb_left_y);
nk_input_button(context, NK_BUTTON_LEFT, controllerState.thumb_left_x, controllerState.thumb_left_y, controllerState.buttons[CONTROLLER_A_BUTTON]);
nk_input_button(context, NK_BUTTON_MIDDLE, controllerState.thumb_left_x, controllerState.thumb_left_y, controllerState.buttons[CONTROLLER_X_BUTTON]);
nk_input_button(context, NK_BUTTON_RIGHT, controllerState.thumb_left_x, controllerState.thumb_left_y, controllerState.buttons[CONTROLLER_B_BUTTON]);
}
nk_input_end(context);
}
+44 -2
View File
@@ -11,14 +11,53 @@
#define NK_INCLUDE_DEFAULT_FONT
#include "nuklear.h"
typedef struct MouseState
typedef struct ControllerState
{
int thumb_left_x;
int thumb_left_y;
int thumb_left_dx;
int thumb_left_dy;
int thumb_right_x;
int thumb_right_y;
int thumb_right_dx;
int thumb_right_dy;
float velocity_left_x;
float velocity_left_y;
float velocity_right_x;
float velocity_right_y;
bool buttons[16];
} ControllerState;
typedef enum CONTROLLER_BUTTON
{
CONTROLLER_A_BUTTON = 0,
CONTROLLER_B_BUTTON = 1,
CONTROLLER_X_BUTTON = 2,
CONTROLLER_Y_BUTTON = 3,
CONTROLLER_BLACK_BUTTON = 4,
CONTROLLER_WHITE_BUTTON = 5,
CONTROLLER_LTRIGGER_BUTTON = 6,
CONTROLLER_RTRIGGER_BUTTON = 7,
CONTROLLER_DPAD_UP_BUTTON = 8,
CONTROLLER_DPAD_DOWN_BUTTON = 9,
CONTROLLER_DPAD_LEFT_BUTTON = 10,
CONTROLLER_DPAD_RIGHT_BUTTON = 11,
CONTROLLER_START_BUTTON = 12,
CONTROLLER_BACK_BUTTON = 13,
CONTROLLER_LTHUMB_BUTTON = 14,
CONTROLLER_RTHUMB_BUTTON = 15,
} CONTROLLER_BUTTON;
typedef struct MouseState
{
int x;
int y;
int dx;
int dy;
int dz;
bool button[5];
bool buttons[5];
} MouseState;
typedef enum MOUSE_BUTTON
@@ -52,9 +91,12 @@ class input_manager
{
public:
static void init();
static void process_controller();
static void process_mouse();
static void process_keyboard();
static bool controller_pressed(CONTROLLER_BUTTON button, int port);
static bool mouse_pressed(MOUSE_BUTTON button, int port);
static bool try_get_controller_state(int port, ControllerState* controllerState);
static bool try_get_mouse_state(int port, MouseState* mouseState);
static bool has_mouse(int port);
static bool try_get_keyboard_state(int port, KeyboardState* keyboardState);
+14
View File
@@ -1,8 +1,22 @@
#include "math.h"
#include <xtl.h>
int math::clamp_int(int value, int min, int max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}
float math::clamp_float(float value, float min, float max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}
float math::copy_sign(float a, float b)
{
return (b >= 0.0f) ? fabsf(a) : -fabsf(a);
}
+2
View File
@@ -4,4 +4,6 @@ class math
{
public:
static int clamp_int(int value, int min, int max);
static float clamp_float(float value, float min, float max);
static float copy_sign(float a, float b);
};