2021-08-14 16:00:50 -04:00
|
|
|
/*!
|
|
|
|
* @file newpad.cpp
|
|
|
|
* PC-port specific cpad implementation on the C kernel. Monitors button inputs.
|
|
|
|
* Actual input detection is done through window events and is gfx pipeline-dependent.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "newpad.h"
|
|
|
|
#include "common/log/log.h"
|
2022-04-07 20:02:33 -04:00
|
|
|
#include "common/util/Assert.h"
|
2021-08-14 16:00:50 -04:00
|
|
|
#include "game/graphics/pipelines/opengl.h" // for GLFW macros
|
|
|
|
|
|
|
|
namespace Pad {
|
|
|
|
|
|
|
|
/*
|
|
|
|
********************************
|
|
|
|
* Key checking
|
|
|
|
********************************
|
|
|
|
*/
|
|
|
|
|
2022-04-07 20:02:33 -04:00
|
|
|
constexpr int NUM_KEYS = GLFW_KEY_LAST + 1;
|
|
|
|
// key-down status of any detected key.
|
|
|
|
bool g_key_status[NUM_KEYS] = {0};
|
|
|
|
// key-down status of any detected key. this is buffered for the remainder of a frame.
|
|
|
|
bool g_buffered_key_status[NUM_KEYS] = {0};
|
2021-08-14 16:00:50 -04:00
|
|
|
|
2021-09-26 11:41:58 -04:00
|
|
|
bool g_gamepad_buttons[(int)Button::Max] = {0};
|
2022-03-25 18:26:42 -04:00
|
|
|
float g_gamepad_analogs[(int)Analog::Max] = {0};
|
|
|
|
|
|
|
|
struct GamepadState {
|
|
|
|
int gamepad_idx = -1;
|
|
|
|
} g_gamepads;
|
2021-09-26 11:41:58 -04:00
|
|
|
|
2021-08-15 22:50:36 -04:00
|
|
|
// input mode for controller mapping
|
2021-08-16 02:44:05 -04:00
|
|
|
InputModeStatus input_mode = InputModeStatus::Disabled;
|
2021-12-04 15:34:03 -05:00
|
|
|
int input_mode_pad = 0;
|
2021-08-15 22:50:36 -04:00
|
|
|
u64 input_mode_key = -1;
|
|
|
|
u64 input_mode_mod = 0;
|
2021-08-16 02:44:05 -04:00
|
|
|
u64 input_mode_index = 0;
|
2021-08-16 09:57:15 -04:00
|
|
|
MappingInfo g_input_mode_mapping;
|
2021-08-15 22:50:36 -04:00
|
|
|
|
2021-08-14 16:00:50 -04:00
|
|
|
void ForceClearKeys() {
|
2022-04-07 20:02:33 -04:00
|
|
|
for (auto& key : g_key_status) {
|
|
|
|
key = false;
|
|
|
|
}
|
|
|
|
for (auto& key : g_buffered_key_status) {
|
|
|
|
key = false;
|
|
|
|
}
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClearKeys() {
|
2022-04-07 20:02:33 -04:00
|
|
|
for (int key = 0; key < NUM_KEYS; key++) {
|
|
|
|
g_buffered_key_status[key] = g_key_status[key];
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnKeyPress(int key) {
|
2021-08-16 02:44:05 -04:00
|
|
|
if (input_mode == InputModeStatus::Enabled) {
|
2021-08-15 22:50:36 -04:00
|
|
|
if (key == GLFW_KEY_ESCAPE) {
|
2021-08-16 02:44:05 -04:00
|
|
|
ExitInputMode(true);
|
2021-08-15 22:50:36 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
input_mode_key = key;
|
2021-08-16 09:57:15 -04:00
|
|
|
MapButton(g_input_mode_mapping, (Button)(input_mode_index++), input_mode_pad, key);
|
|
|
|
if (input_mode_index >= (u64)Button::Max) {
|
2021-08-16 02:44:05 -04:00
|
|
|
ExitInputMode(false);
|
|
|
|
}
|
2021-08-15 22:50:36 -04:00
|
|
|
return;
|
|
|
|
}
|
2021-08-14 16:00:50 -04:00
|
|
|
// set absolute key status
|
2022-04-07 20:02:33 -04:00
|
|
|
ASSERT(key < NUM_KEYS);
|
|
|
|
g_key_status[key] = true;
|
2021-08-14 16:00:50 -04:00
|
|
|
// set buffered key status
|
2022-04-07 20:02:33 -04:00
|
|
|
g_buffered_key_status[key] = true;
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void OnKeyRelease(int key) {
|
2021-08-16 02:44:05 -04:00
|
|
|
if (input_mode == InputModeStatus::Enabled) {
|
2021-08-15 22:50:36 -04:00
|
|
|
return;
|
|
|
|
}
|
2022-04-07 20:02:33 -04:00
|
|
|
ASSERT(key < NUM_KEYS);
|
|
|
|
g_key_status[key] = false;
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
********************************
|
|
|
|
* Pad checking
|
|
|
|
********************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int CheckPadIdx(int pad) {
|
|
|
|
if (pad < 0 || pad > CONTROLLER_COUNT) {
|
2021-09-21 18:40:38 -04:00
|
|
|
lg::error("Invalid pad {}", pad);
|
|
|
|
return -1;
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
2021-09-21 18:40:38 -04:00
|
|
|
return pad;
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// returns 1 if button is pressed. returns 0 if invalid or not pressed.
|
|
|
|
int IsPressed(MappingInfo& mapping, Button button, int pad = 0) {
|
2021-09-21 18:40:38 -04:00
|
|
|
if (CheckPadIdx(pad) == -1) {
|
|
|
|
return 0;
|
|
|
|
}
|
2021-09-26 11:41:58 -04:00
|
|
|
|
2021-12-04 15:34:03 -05:00
|
|
|
if (pad == 0 && g_gamepad_buttons[(int)button]) {
|
2021-09-26 11:41:58 -04:00
|
|
|
return 1;
|
|
|
|
}
|
2021-09-21 18:40:38 -04:00
|
|
|
auto key = mapping.pad_mapping[pad][(int)button];
|
2021-08-14 16:00:50 -04:00
|
|
|
if (key == -1)
|
|
|
|
return 0;
|
|
|
|
auto& keymap = mapping.buffer_mode ? g_buffered_key_status : g_key_status;
|
2022-04-07 20:02:33 -04:00
|
|
|
ASSERT(key < NUM_KEYS);
|
|
|
|
return keymap[key];
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
|
2021-11-13 22:41:15 -05:00
|
|
|
// returns the value of the analog axis (in the future, likely pressure sensitive if we support it?)
|
|
|
|
// if invalid or otherwise -- returns 127 (analog stick neutral position)
|
2021-11-15 20:07:10 -05:00
|
|
|
int AnalogValue(MappingInfo& /*mapping*/, Analog analog, int pad = 0) {
|
2022-03-25 18:26:42 -04:00
|
|
|
float input = 0.0f;
|
|
|
|
|
2021-11-13 22:41:15 -05:00
|
|
|
if (CheckPadIdx(pad) == -1) {
|
2022-03-25 18:26:42 -04:00
|
|
|
// Pad out of range, return a stable value
|
2021-11-13 22:41:15 -05:00
|
|
|
return 127;
|
|
|
|
}
|
2022-03-25 18:26:42 -04:00
|
|
|
|
|
|
|
if (g_gamepads.gamepad_idx == -1) { // Gamepad not present - use keyboard
|
|
|
|
|
|
|
|
// Movement controls mapped to WASD keys
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_W] && analog == Analog::Left_Y)
|
|
|
|
input += -1.0f;
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_S] && analog == Analog::Left_Y)
|
|
|
|
input += 1.0f;
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_A] && analog == Analog::Left_X)
|
|
|
|
input += -1.0f;
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_D] && analog == Analog::Left_X)
|
|
|
|
input += 1.0f;
|
|
|
|
|
|
|
|
// Camera controls mapped to IJKL keys
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_I] && analog == Analog::Right_Y)
|
|
|
|
input += -1.0f;
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_K] && analog == Analog::Right_Y)
|
|
|
|
input += 1.0f;
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_J] && analog == Analog::Right_X)
|
|
|
|
input += -1.0f;
|
|
|
|
if (g_buffered_key_status[GLFW_KEY_L] && analog == Analog::Right_X)
|
|
|
|
input += 1.0f;
|
|
|
|
|
|
|
|
} else { // Gamepad present
|
|
|
|
input = g_gamepad_analogs[(int)analog];
|
|
|
|
}
|
|
|
|
|
|
|
|
// GLFW provides float in range -1 to 1, caller expects 0-255
|
|
|
|
const float input_low = -1.0f;
|
|
|
|
const float input_high = 1.0f;
|
|
|
|
const int output_low = 0;
|
|
|
|
const int output_high = 255;
|
|
|
|
|
|
|
|
// Map from input to output range
|
|
|
|
return int((input - input_low) * (output_high - output_low) / (input_high - input_low) +
|
|
|
|
output_low);
|
2021-11-13 22:41:15 -05:00
|
|
|
}
|
|
|
|
|
2021-08-14 16:00:50 -04:00
|
|
|
// map a button on a pad to a key
|
|
|
|
void MapButton(MappingInfo& mapping, Button button, int pad, int key) {
|
|
|
|
// check if pad is valid. dont map buttons with invalid pads.
|
2021-09-21 18:40:38 -04:00
|
|
|
if (CheckPadIdx(pad) == -1) {
|
2021-08-14 16:00:50 -04:00
|
|
|
return;
|
2021-09-21 18:40:38 -04:00
|
|
|
}
|
2021-08-14 16:00:50 -04:00
|
|
|
|
|
|
|
mapping.pad_mapping[pad][(int)button] = key;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset button mappings
|
|
|
|
void DefaultMapping(MappingInfo& mapping) {
|
|
|
|
// make every button invalid
|
|
|
|
for (int p = 0; p < CONTROLLER_COUNT; ++p) {
|
|
|
|
for (int i = 0; i < (int)Button::Max; ++i) {
|
|
|
|
MapButton(mapping, (Button)i, p, -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-25 18:26:42 -04:00
|
|
|
// R1 / L1
|
|
|
|
MapButton(mapping, Button::L1, 0, GLFW_KEY_Q);
|
|
|
|
MapButton(mapping, Button::R1, 0, GLFW_KEY_O);
|
|
|
|
|
|
|
|
// R2 / L2
|
|
|
|
MapButton(mapping, Button::L2, 0, GLFW_KEY_1);
|
|
|
|
MapButton(mapping, Button::R2, 0, GLFW_KEY_P);
|
2021-08-31 11:05:03 -04:00
|
|
|
|
2021-08-14 16:00:50 -04:00
|
|
|
// face buttons
|
2022-03-25 18:26:42 -04:00
|
|
|
MapButton(mapping, Button::Ecks, 0, GLFW_KEY_SPACE);
|
|
|
|
MapButton(mapping, Button::Square, 0, GLFW_KEY_F);
|
|
|
|
MapButton(mapping, Button::Triangle, 0, GLFW_KEY_R);
|
|
|
|
MapButton(mapping, Button::Circle, 0, GLFW_KEY_E);
|
2021-08-14 16:00:50 -04:00
|
|
|
|
|
|
|
// dpad
|
|
|
|
MapButton(mapping, Button::Up, 0, GLFW_KEY_UP);
|
|
|
|
MapButton(mapping, Button::Right, 0, GLFW_KEY_RIGHT);
|
|
|
|
MapButton(mapping, Button::Down, 0, GLFW_KEY_DOWN);
|
|
|
|
MapButton(mapping, Button::Left, 0, GLFW_KEY_LEFT);
|
2021-08-29 11:13:06 -04:00
|
|
|
|
2021-09-06 20:35:03 -04:00
|
|
|
// start for progress
|
|
|
|
MapButton(mapping, Button::Start, 0, GLFW_KEY_ENTER);
|
|
|
|
|
2021-08-29 11:13:06 -04:00
|
|
|
// l3/r3 for menu
|
|
|
|
MapButton(mapping, Button::L3, 0, GLFW_KEY_COMMA);
|
|
|
|
MapButton(mapping, Button::R3, 0, GLFW_KEY_PERIOD);
|
2021-08-14 16:00:50 -04:00
|
|
|
}
|
|
|
|
|
2021-08-16 02:44:05 -04:00
|
|
|
void EnterInputMode() {
|
|
|
|
input_mode = InputModeStatus::Enabled;
|
|
|
|
input_mode_index = 0;
|
|
|
|
input_mode_pad = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExitInputMode(bool canceled) {
|
|
|
|
input_mode = canceled ? InputModeStatus::Canceled : InputModeStatus::Disabled;
|
2021-08-15 22:50:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
u64 input_mode_get() {
|
2021-08-16 02:44:05 -04:00
|
|
|
return (u64)input_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 input_mode_get_key() {
|
2021-08-15 22:50:36 -04:00
|
|
|
return input_mode_key;
|
|
|
|
}
|
|
|
|
|
2021-08-16 02:44:05 -04:00
|
|
|
u64 input_mode_get_index() {
|
|
|
|
return input_mode_index;
|
|
|
|
}
|
|
|
|
|
2021-12-04 15:34:03 -05:00
|
|
|
void input_mode_pad_set(s64 idx) {
|
|
|
|
input_mode_pad = idx;
|
|
|
|
}
|
|
|
|
|
2021-09-26 11:41:58 -04:00
|
|
|
/*
|
|
|
|
********************************
|
|
|
|
* Gamepad Support
|
|
|
|
********************************
|
|
|
|
*/
|
|
|
|
|
2021-11-15 19:05:28 -05:00
|
|
|
void check_gamepad() {
|
|
|
|
if (g_gamepads.gamepad_idx == -1) {
|
|
|
|
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; i++) {
|
|
|
|
if (glfwJoystickPresent(i) && glfwJoystickIsGamepad(i)) {
|
|
|
|
g_gamepads.gamepad_idx = i;
|
|
|
|
lg::info("Using joystick {}: {}, {}", i, glfwGetJoystickName(i), glfwGetGamepadName(i));
|
|
|
|
break;
|
|
|
|
}
|
2021-09-26 11:41:58 -04:00
|
|
|
}
|
2021-12-04 15:34:03 -05:00
|
|
|
} else if (!glfwJoystickPresent(g_gamepads.gamepad_idx)) {
|
|
|
|
lg::info("Gamepad has been disconnected");
|
|
|
|
g_gamepads.gamepad_idx = -1;
|
2021-09-26 11:41:58 -04:00
|
|
|
}
|
2021-11-15 19:05:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void initialize() {
|
|
|
|
check_gamepad();
|
2021-09-26 11:41:58 -04:00
|
|
|
if (g_gamepads.gamepad_idx == -1) {
|
|
|
|
lg::info("No joysticks found.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 19:05:28 -05:00
|
|
|
void clear_gamepads() {
|
|
|
|
for (int i = 0; i < (int)Button::Max; ++i) {
|
|
|
|
g_gamepad_buttons[i] = false;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
2022-03-25 18:26:42 -04:00
|
|
|
g_gamepad_analogs[i] = 0;
|
2021-11-15 19:05:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-26 11:41:58 -04:00
|
|
|
void update_gamepads() {
|
2021-11-15 19:05:28 -05:00
|
|
|
check_gamepad();
|
|
|
|
|
2021-09-26 11:41:58 -04:00
|
|
|
if (g_gamepads.gamepad_idx == -1) {
|
2021-12-04 15:34:03 -05:00
|
|
|
clear_gamepads();
|
2021-09-26 11:41:58 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLFWgamepadstate state;
|
|
|
|
glfwGetGamepadState(g_gamepads.gamepad_idx, &state);
|
|
|
|
|
|
|
|
constexpr std::pair<Button, int> gamepad_map[] = {
|
|
|
|
{Button::Select, GLFW_GAMEPAD_BUTTON_BACK},
|
|
|
|
{Button::L3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB},
|
|
|
|
{Button::R3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB},
|
|
|
|
{Button::Start, GLFW_GAMEPAD_BUTTON_START},
|
|
|
|
{Button::Up, GLFW_GAMEPAD_BUTTON_DPAD_UP},
|
|
|
|
{Button::Right, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT},
|
|
|
|
{Button::Down, GLFW_GAMEPAD_BUTTON_DPAD_DOWN},
|
|
|
|
{Button::Left, GLFW_GAMEPAD_BUTTON_DPAD_LEFT},
|
|
|
|
{Button::L1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER},
|
|
|
|
{Button::R1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER},
|
|
|
|
{Button::Triangle, GLFW_GAMEPAD_BUTTON_TRIANGLE},
|
|
|
|
{Button::Circle, GLFW_GAMEPAD_BUTTON_CIRCLE},
|
|
|
|
{Button::X, GLFW_GAMEPAD_BUTTON_CROSS},
|
|
|
|
{Button::Square, GLFW_GAMEPAD_BUTTON_SQUARE}};
|
|
|
|
|
2021-11-13 22:41:15 -05:00
|
|
|
constexpr std::pair<Analog, int> gamepad_analog_map[] = {
|
|
|
|
{Analog::Left_X, GLFW_GAMEPAD_AXIS_LEFT_X},
|
|
|
|
{Analog::Left_Y, GLFW_GAMEPAD_AXIS_LEFT_Y},
|
|
|
|
{Analog::Right_X, GLFW_GAMEPAD_AXIS_RIGHT_X},
|
|
|
|
{Analog::Right_Y, GLFW_GAMEPAD_AXIS_RIGHT_Y}};
|
|
|
|
|
2021-09-26 11:41:58 -04:00
|
|
|
for (const auto& [button, idx] : gamepad_map) {
|
|
|
|
g_gamepad_buttons[(int)button] = state.buttons[idx];
|
|
|
|
}
|
2021-11-13 20:44:17 -05:00
|
|
|
|
|
|
|
g_gamepad_buttons[(int)Button::L2] = state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] > 0;
|
|
|
|
g_gamepad_buttons[(int)Button::R2] = state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] > 0;
|
2021-11-13 22:41:15 -05:00
|
|
|
|
|
|
|
for (const auto& [analog_vector, idx] : gamepad_analog_map) {
|
|
|
|
g_gamepad_analogs[(int)analog_vector] = state.axes[idx];
|
|
|
|
}
|
2021-09-26 11:41:58 -04:00
|
|
|
}
|
|
|
|
|
2021-08-14 16:00:50 -04:00
|
|
|
}; // namespace Pad
|