mirror of
https://github.com/open-goal/jak-project
synced 2026-07-04 21:35:47 -04:00
Added first working instance of controller/keyboard re-mapper (#1702)
* Added First working instance of controller/keyboard re-mapper * Fixed clang formatting issues * Updated newpad.cpp to inverse analog y-axis to make json labelling consistent * Added mouse sensitivity options for X and Y axis in json, removed scroll mouse support, and other changes requested in feedback * Added option to have ImGui debug menu appear on start up and remove hard coded set_imgui_visible calls * Added newpad unit tests and updated function names to better describe intended functionalities * Fixed formatting issue in newpad unit test * Removed rumble unit test new pad * Fixed codacy static analysis issues * Fixed Linux build issues * Implemented github feedback * Implemented updated github feedback * Fixed formatting errors * Updated Pad::CheckPadIdx * Implemented changes based on latest github feedback * Implemented changes based on github feedback Co-authored-by: animalstyletaco <animalstyletaco95@gmail.com>
This commit is contained in:
@@ -92,7 +92,6 @@ int InitMainDisplay(int width,
|
||||
lg::error("Failed to make main display.");
|
||||
return 1;
|
||||
}
|
||||
display->set_imgui_visible(true);
|
||||
set_main_display(display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+178
-30
@@ -14,6 +14,7 @@
|
||||
#include "common/log/log.h"
|
||||
#include "common/symbols.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/json_util.h"
|
||||
|
||||
#include "game/common/file_paths.h"
|
||||
#include "game/kernel/common/kscheme.h"
|
||||
@@ -42,8 +43,8 @@ void InitSettings(GfxSettings& settings) {
|
||||
settings.pad_mapping_info.buffer_mode = true;
|
||||
// debug input settings
|
||||
settings.pad_mapping_info.debug = true;
|
||||
// use a default mapping
|
||||
Pad::DefaultMapping(settings.pad_mapping_info);
|
||||
|
||||
Pad::DefaultMapping(Gfx::g_settings.pad_mapping_info);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -53,36 +54,180 @@ namespace Gfx {
|
||||
std::function<void()> vsync_callback;
|
||||
GfxGlobalSettings g_global_settings;
|
||||
GfxSettings g_settings;
|
||||
|
||||
Pad::MappingInfo& get_button_mapping() {
|
||||
return g_settings.pad_mapping_info;
|
||||
}
|
||||
|
||||
// const std::vector<const GfxRendererModule*> renderers = {&moduleOpenGL};
|
||||
|
||||
// TODO serialize
|
||||
void LoadSettings() {
|
||||
const auto filename = file_util::get_file_path({GAME_CONFIG_DIR_NAME, SETTINGS_GFX_FILE_NAME});
|
||||
if (fs::exists(filename)) {
|
||||
// this is just wrong LOL
|
||||
FILE* fp = file_util::open_file(filename.c_str(), "rb");
|
||||
lg::info("Found graphics configuration file. Checking version.");
|
||||
u64 version;
|
||||
fread(&version, sizeof(u64), 1, fp);
|
||||
if (version == GfxSettings::CURRENT_VERSION) {
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fread(&g_settings, sizeof(GfxSettings), 1, fp);
|
||||
lg::info("Loaded graphics configuration file.");
|
||||
} else {
|
||||
// TODO upgrade func
|
||||
lg::info("Detected graphics configuration file from old version. Ignoring.");
|
||||
// Not crazy about this declaration
|
||||
const std::pair<std::string, Pad::Button> gamepad_map[] = {{"Select", Pad::Button::Select},
|
||||
{"L3", Pad::Button::L3},
|
||||
{"R3", Pad::Button::R3},
|
||||
{"Start", Pad::Button::Start},
|
||||
{"Up", Pad::Button::Up},
|
||||
{"Right", Pad::Button::Right},
|
||||
{"Down", Pad::Button::Down},
|
||||
{"Left", Pad::Button::Left},
|
||||
{"L1", Pad::Button::L1},
|
||||
{"R1", Pad::Button::R1},
|
||||
{"Triangle", Pad::Button::Triangle},
|
||||
{"Circle", Pad::Button::Circle},
|
||||
{"X", Pad::Button::X},
|
||||
{"Square", Pad::Button::Square}};
|
||||
|
||||
const std::pair<std::string, Pad::Analog> analog_map[] = {
|
||||
{"Left X Axis", Pad::Analog::Left_X},
|
||||
{"Left Y Axis", Pad::Analog::Left_Y},
|
||||
{"Right X Axis", Pad::Analog::Right_X},
|
||||
{"Right Y Axis", Pad::Analog::Right_Y},
|
||||
};
|
||||
|
||||
bool g_is_debug_menu_visible_on_startup = false;
|
||||
|
||||
bool get_debug_menu_visible_on_startup() {
|
||||
return g_is_debug_menu_visible_on_startup;
|
||||
}
|
||||
|
||||
void DumpToJson(ghc::filesystem::path& filename) {
|
||||
nlohmann::json json;
|
||||
json["Debug Menu Visibility"] = false; // Assume start up debug display is disabled
|
||||
auto& peripherals_json = json["Peripherals"];
|
||||
|
||||
for (uint32_t i = 0; i < Pad::CONTROLLER_COUNT; ++i) {
|
||||
nlohmann::json peripheral_json;
|
||||
peripheral_json["ID"] = i + 1;
|
||||
|
||||
auto& controller_json = peripheral_json["Controller"];
|
||||
auto& controller_buttons_json = controller_json["Buttons"];
|
||||
for (const auto& [name, value] : gamepad_map) {
|
||||
controller_buttons_json[name] =
|
||||
g_settings.pad_mapping_info.controller_button_mapping[i][(int)value];
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
auto& keyboard_json = peripheral_json["Keyboard+Mouse"];
|
||||
auto& keyboard_buttons_json = keyboard_json["Buttons"];
|
||||
for (const auto& [name, value] : gamepad_map) {
|
||||
keyboard_buttons_json[name] =
|
||||
g_settings.pad_mapping_info.keyboard_button_mapping[i][(int)value];
|
||||
}
|
||||
|
||||
auto& keyboard_analogs_json = keyboard_json["Analog"];
|
||||
for (const auto& [name, value] : analog_map) {
|
||||
if (g_settings.pad_mapping_info.keyboard_analog_mapping[i][(int)value].mode ==
|
||||
Pad::AnalogMappingMode::AnalogInput) {
|
||||
keyboard_analogs_json[name]["Axis Id"] =
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[i][(int)value].axis_id;
|
||||
} else {
|
||||
keyboard_analogs_json[name]["Positive Key"] =
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[i][(int)value].positive_key;
|
||||
keyboard_analogs_json[name]["Negative Key"] =
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[i][(int)value].negative_key;
|
||||
}
|
||||
}
|
||||
peripheral_json["X-Axis Mouse Sensitivity"] =
|
||||
g_settings.pad_mapping_info.mouse_x_axis_sensitivities[i];
|
||||
peripheral_json["Y-Axis Mouse Sensitivity"] =
|
||||
g_settings.pad_mapping_info.mouse_y_axis_sensitivities[i];
|
||||
peripherals_json.emplace_back(peripheral_json);
|
||||
}
|
||||
|
||||
file_util::write_text_file(filename, json.dump(4));
|
||||
}
|
||||
|
||||
void SavePeripheralSettings() {
|
||||
auto filename = (file_util::get_user_config_dir() / "controller" / "controller-settings.json");
|
||||
file_util::create_dir_if_needed_for_file(filename);
|
||||
|
||||
DumpToJson(filename);
|
||||
lg::info("Saved graphics configuration file.");
|
||||
}
|
||||
|
||||
void LoadPeripheralSettings(const ghc::filesystem::path& filepath) {
|
||||
Pad::DefaultMapping(g_settings.pad_mapping_info);
|
||||
|
||||
auto file_txt = file_util::read_text_file(filepath);
|
||||
auto configuration = parse_commented_json(file_txt, filepath.string());
|
||||
|
||||
if (configuration.find("Debug Menu Visibility") != configuration.end()) {
|
||||
g_is_debug_menu_visible_on_startup = configuration["Debug Menu Visibility"].get<bool>();
|
||||
}
|
||||
|
||||
int controller_index = 0;
|
||||
for (const auto& peripheral : configuration["Peripherals"]) {
|
||||
auto& controller_buttons_json = peripheral["Controller"]["Buttons"];
|
||||
auto& keyboard_buttons_json = peripheral["Keyboard+Mouse"]["Buttons"];
|
||||
|
||||
for (const auto& [name, button] : gamepad_map) {
|
||||
if (controller_buttons_json.find(name) != controller_buttons_json.end()) {
|
||||
g_settings.pad_mapping_info.controller_button_mapping[controller_index][(int)button] =
|
||||
controller_buttons_json[name].get<int>();
|
||||
} else {
|
||||
lg::warn(
|
||||
"Controller button override not found for {}. Using controller default value: {}", name,
|
||||
g_settings.pad_mapping_info.controller_button_mapping[controller_index][(int)button]);
|
||||
}
|
||||
|
||||
if (keyboard_buttons_json.find(name) != keyboard_buttons_json.end()) {
|
||||
g_settings.pad_mapping_info.keyboard_button_mapping[controller_index][(int)button] =
|
||||
keyboard_buttons_json[name].get<int>();
|
||||
} else {
|
||||
lg::warn(
|
||||
"Keyboard button override not found for {}. Using keyboard default value: {}", name,
|
||||
g_settings.pad_mapping_info.keyboard_button_mapping[controller_index][(int)button]);
|
||||
}
|
||||
}
|
||||
|
||||
auto& keyboard_analogs_json = peripheral["Keyboard+Mouse"]["Analog"];
|
||||
for (const auto& [name, value] : analog_map) {
|
||||
Pad::AnalogMappingInfo analog_mapping;
|
||||
if (keyboard_analogs_json[name].contains("Axis Id") == true) {
|
||||
analog_mapping.mode = Pad::AnalogMappingMode::AnalogInput;
|
||||
analog_mapping.axis_id = keyboard_analogs_json[name]["Axis Id"].get<int>();
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[controller_index][(int)value] =
|
||||
analog_mapping;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keyboard_analogs_json[name].contains("Positive Key") == true) {
|
||||
analog_mapping.positive_key = keyboard_analogs_json[name]["Positive Key"].get<int>();
|
||||
} else {
|
||||
lg::warn("Keyboard analog override not found for {}. Using keyboard default value: {}",
|
||||
name,
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[controller_index][(int)value]
|
||||
.positive_key);
|
||||
}
|
||||
|
||||
if (keyboard_analogs_json[name].contains("Negative Key") == true) {
|
||||
analog_mapping.negative_key = keyboard_analogs_json[name]["Negative Key"].get<int>();
|
||||
} else {
|
||||
lg::warn("Keyboard analog override not found for {}. Using keyboard default value: {}",
|
||||
name,
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[controller_index][(int)value]
|
||||
.negative_key);
|
||||
}
|
||||
g_settings.pad_mapping_info.keyboard_analog_mapping[controller_index][(int)value] =
|
||||
analog_mapping;
|
||||
}
|
||||
g_settings.pad_mapping_info.mouse_x_axis_sensitivities[controller_index] =
|
||||
peripheral["X-Axis Mouse Sensitivity"].get<double>();
|
||||
g_settings.pad_mapping_info.mouse_y_axis_sensitivities[controller_index] =
|
||||
peripheral["Y-Axis Mouse Sensitivity"].get<double>();
|
||||
controller_index++;
|
||||
}
|
||||
}
|
||||
|
||||
void SaveSettings() {
|
||||
const auto filename = file_util::get_file_path({GAME_CONFIG_DIR_NAME, SETTINGS_GFX_FILE_NAME});
|
||||
file_util::create_dir_if_needed(file_util::get_file_path({GAME_CONFIG_DIR_NAME}));
|
||||
FILE* fp = file_util::open_file(filename.c_str(), "wb");
|
||||
fwrite(&g_settings, sizeof(GfxSettings), 1, fp);
|
||||
fclose(fp);
|
||||
lg::info("Saved graphics configuration file.");
|
||||
void LoadSettings() {
|
||||
auto filename = (file_util::get_user_config_dir() / "controller" / "controller-settings.json");
|
||||
if (fs::exists(filename)) {
|
||||
LoadPeripheralSettings(filename);
|
||||
lg::info("Loaded graphics configuration file.");
|
||||
return;
|
||||
} else {
|
||||
SavePeripheralSettings();
|
||||
lg::info("Couldn't find controller-settings.json creating new controller settings file.");
|
||||
}
|
||||
}
|
||||
|
||||
const GfxRendererModule* GetRenderer(GfxPipeline pipeline) {
|
||||
@@ -319,7 +464,7 @@ void input_mode_save() {
|
||||
g_settings.pad_mapping_info_backup = g_settings.pad_mapping_info; // copy to backup
|
||||
g_settings.pad_mapping_info = Pad::g_input_mode_mapping; // set current mapping
|
||||
|
||||
SaveSettings();
|
||||
SavePeripheralSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,15 +473,18 @@ s64 get_mapped_button(s64 pad, s64 button) {
|
||||
lg::error("Invalid parameters to get_mapped_button({}, {})", pad, button);
|
||||
return -1;
|
||||
}
|
||||
return (s64)g_settings.pad_mapping_info.pad_mapping[pad][button];
|
||||
|
||||
return (Pad::GetGamepadState(pad) > -1)
|
||||
? (s64)g_settings.pad_mapping_info.controller_button_mapping[pad][button]
|
||||
: (s64)g_settings.pad_mapping_info.keyboard_button_mapping[pad][button];
|
||||
}
|
||||
|
||||
int PadIsPressed(Pad::Button button, int port) {
|
||||
return Pad::IsPressed(g_settings.pad_mapping_info, button, port);
|
||||
}
|
||||
|
||||
int PadAnalogValue(Pad::Analog analog, int port) {
|
||||
return Pad::AnalogValue(g_settings.pad_mapping_info, analog, port);
|
||||
int PadGetAnalogValue(Pad::Analog analog, int port) {
|
||||
return Pad::GetAnalogValue(g_settings.pad_mapping_info, analog, port);
|
||||
}
|
||||
|
||||
void SetLod(RendererTreeType tree, int lod) {
|
||||
|
||||
+4
-1
@@ -124,6 +124,8 @@ u32 Init(GameVersion version);
|
||||
void Loop(std::function<bool()> f);
|
||||
u32 Exit();
|
||||
|
||||
Pad::MappingInfo& get_button_mapping();
|
||||
|
||||
u32 vsync();
|
||||
void register_vsync_callback(std::function<void()> f);
|
||||
void clear_vsync_callback();
|
||||
@@ -152,9 +154,10 @@ void set_msaa(int samples);
|
||||
void input_mode_set(u32 enable);
|
||||
void input_mode_save();
|
||||
s64 get_mapped_button(s64 pad, s64 button);
|
||||
bool get_debug_menu_visible_on_startup();
|
||||
|
||||
int PadIsPressed(Pad::Button button, int port);
|
||||
int PadAnalogValue(Pad::Analog analog, int port);
|
||||
int PadGetAnalogValue(Pad::Analog analog, int port);
|
||||
|
||||
// matching enum in kernel-defs.gc !!
|
||||
enum class RendererTreeType { NONE = 0, TFRAG3 = 1, TIE3 = 2, INVALID };
|
||||
|
||||
@@ -78,6 +78,11 @@ struct GraphicsData {
|
||||
|
||||
std::unique_ptr<GraphicsData> g_gfx_data;
|
||||
|
||||
std::atomic<int> g_cursor_input_mode = GLFW_CURSOR_DISABLED;
|
||||
bool is_cursor_position_valid = false;
|
||||
double last_cursor_x_position = 0;
|
||||
double last_cursor_y_position = 0;
|
||||
|
||||
struct {
|
||||
bool callbacks_registered = false;
|
||||
GLFWmonitor** monitors;
|
||||
@@ -209,6 +214,7 @@ static std::shared_ptr<GfxDisplay> gl_make_display(int width,
|
||||
}
|
||||
|
||||
auto display = std::make_shared<GLDisplay>(window, is_main);
|
||||
|
||||
// lg::debug("init display #x{:x}", (uintptr_t)display);
|
||||
|
||||
// setup imgui
|
||||
@@ -255,6 +261,16 @@ GLDisplay::GLDisplay(GLFWwindow* window, bool is_main) : m_window(window) {
|
||||
display->on_key(window, key, scancode, action, mods);
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(window, [](GLFWwindow* window, int button, int action, int mode) {
|
||||
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
|
||||
display->on_mouse_key(window, button, action, mode);
|
||||
});
|
||||
|
||||
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xposition, double yposition) {
|
||||
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
|
||||
display->on_cursor_position(window, xposition, yposition);
|
||||
});
|
||||
|
||||
glfwSetWindowPosCallback(window, [](GLFWwindow* window, int xpos, int ypos) {
|
||||
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
|
||||
display->on_window_pos(window, xpos, ypos);
|
||||
@@ -289,6 +305,11 @@ GLDisplay::~GLDisplay() {
|
||||
}
|
||||
}
|
||||
|
||||
void GLDisplay::update_cursor_visibility(GLFWwindow* window, bool is_visible) {
|
||||
g_cursor_input_mode = (is_visible) ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED;
|
||||
glfwSetInputMode(window, GLFW_CURSOR, g_cursor_input_mode);
|
||||
}
|
||||
|
||||
void GLDisplay::on_key(GLFWwindow* window, int key, int /*scancode*/, int action, int /*mods*/) {
|
||||
if (action == GlfwKeyAction::Press) {
|
||||
// lg::debug("KEY PRESS: key: {} scancode: {} mods: {:X}", key, scancode, mods);
|
||||
@@ -296,13 +317,63 @@ void GLDisplay::on_key(GLFWwindow* window, int key, int /*scancode*/, int action
|
||||
} else if (action == GlfwKeyAction::Release) {
|
||||
// lg::debug("KEY RELEASE: key: {} scancode: {} mods: {:X}", key, scancode, mods);
|
||||
Pad::OnKeyRelease(key);
|
||||
if ((key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT) &&
|
||||
glfwGetWindowAttrib(window, GLFW_FOCUSED)) {
|
||||
set_imgui_visible(!is_imgui_visible());
|
||||
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
|
||||
if (display != NULL) { // toggle ImGui when pressing Alt
|
||||
if ((key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT) &&
|
||||
glfwGetWindowAttrib(window, GLFW_FOCUSED)) {
|
||||
display->set_imgui_visible(!display->is_imgui_visible());
|
||||
update_cursor_visibility(window, display->is_imgui_visible());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLDisplay::on_mouse_key(GLFWwindow* window, int button, int action, int mode) {
|
||||
int key =
|
||||
button + GLFW_KEY_LAST; // Mouse button index are appended after initial GLFW keys in newpad
|
||||
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT &&
|
||||
g_cursor_input_mode ==
|
||||
GLFW_CURSOR_NORMAL) { // Are there any other mouse buttons we don't want to use?
|
||||
Pad::ClearKey(key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == GlfwKeyAction::Press) {
|
||||
Pad::OnKeyPress(key);
|
||||
} else if (action == GlfwKeyAction::Release) {
|
||||
Pad::OnKeyRelease(key);
|
||||
}
|
||||
}
|
||||
|
||||
void GLDisplay::on_cursor_position(GLFWwindow* window, double xposition, double yposition) {
|
||||
Pad::MappingInfo mapping_info = Gfx::get_button_mapping();
|
||||
if (g_cursor_input_mode == GLFW_CURSOR_NORMAL) {
|
||||
if (is_cursor_position_valid == true) {
|
||||
Pad::ClearAnalogAxisValue(mapping_info, GlfwKeyCustomAxis::CURSOR_X_AXIS);
|
||||
Pad::ClearAnalogAxisValue(mapping_info, GlfwKeyCustomAxis::CURSOR_Y_AXIS);
|
||||
is_cursor_position_valid = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_cursor_position_valid == false) {
|
||||
last_cursor_x_position = xposition;
|
||||
last_cursor_y_position = yposition;
|
||||
is_cursor_position_valid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
double xoffset = xposition - last_cursor_x_position;
|
||||
double yoffset = yposition - last_cursor_y_position;
|
||||
|
||||
Pad::SetAnalogAxisValue(mapping_info, GlfwKeyCustomAxis::CURSOR_X_AXIS, xoffset);
|
||||
Pad::SetAnalogAxisValue(mapping_info, GlfwKeyCustomAxis::CURSOR_Y_AXIS, yoffset);
|
||||
|
||||
last_cursor_x_position = xposition;
|
||||
last_cursor_y_position = yposition;
|
||||
}
|
||||
|
||||
void GLDisplay::on_window_pos(GLFWwindow* /*window*/, int xpos, int ypos) {
|
||||
if (m_fullscreen_target_mode == GfxDisplayMode::Windowed) {
|
||||
m_last_windowed_xpos = xpos;
|
||||
@@ -451,7 +522,8 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) {
|
||||
x = m_last_windowed_xpos;
|
||||
y = m_last_windowed_ypos;
|
||||
} else {
|
||||
// fullscreen -> windowed, use last windowed size but on the monitor previously fullscreened
|
||||
// fullscreen -> windowed, use last windowed size but on the monitor previously
|
||||
// fullscreened
|
||||
int monitorX, monitorY, monitorWidth, monitorHeight;
|
||||
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
|
||||
|
||||
@@ -464,8 +536,8 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) {
|
||||
glfwSetWindowAttrib(m_window, GLFW_DECORATED, GLFW_TRUE);
|
||||
glfwSetWindowFocusCallback(m_window, NULL);
|
||||
glfwSetWindowAttrib(m_window, GLFW_FLOATING, GLFW_FALSE);
|
||||
|
||||
glfwSetWindowMonitor(m_window, NULL, x, y, width, height, GLFW_DONT_CARE);
|
||||
set_imgui_visible(true);
|
||||
|
||||
// these might have changed
|
||||
m_last_windowed_width = width;
|
||||
@@ -480,7 +552,6 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) {
|
||||
glfwSetWindowFocusCallback(m_window, NULL);
|
||||
glfwSetWindowAttrib(m_window, GLFW_FLOATING, GLFW_FALSE);
|
||||
glfwSetWindowMonitor(m_window, monitor, 0, 0, vmode->width, vmode->height, GLFW_DONT_CARE);
|
||||
set_imgui_visible(false);
|
||||
} break;
|
||||
case GfxDisplayMode::Borderless: {
|
||||
// borderless fullscreen
|
||||
@@ -495,7 +566,6 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) {
|
||||
#else
|
||||
glfwSetWindowMonitor(m_window, NULL, x, y, vmode->width, vmode->height, GLFW_DONT_CARE);
|
||||
#endif
|
||||
set_imgui_visible(false);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -602,7 +672,9 @@ void GLDisplay::render() {
|
||||
auto p = scoped_prof("poll-gamepads");
|
||||
glfwPollEvents();
|
||||
glfwMakeContextCurrent(m_window);
|
||||
Pad::update_gamepads();
|
||||
|
||||
auto& mapping_info = Gfx::get_button_mapping();
|
||||
Pad::update_gamepads(mapping_info);
|
||||
}
|
||||
|
||||
// imgui start of frame
|
||||
@@ -761,13 +833,15 @@ void gl_send_chain(const void* data, u32 offset) {
|
||||
// we copy the dma data and give a copy of it to the render.
|
||||
// the copy has a few advantages:
|
||||
// - if the game code has a bug and corrupts the DMA buffer, the renderer won't see it.
|
||||
// - the copied DMA is much smaller than the entire game memory, so it can be dumped to a file
|
||||
// - the copied DMA is much smaller than the entire game memory, so it can be dumped to a
|
||||
// file
|
||||
// separate of the entire RAM.
|
||||
// - it verifies the DMA data is valid early on.
|
||||
// but it may also be pretty expensive. Both the renderer and the game wait on this to complete.
|
||||
// but it may also be pretty expensive. Both the renderer and the game wait on this to
|
||||
// complete.
|
||||
|
||||
// The renderers should just operate on DMA chains, so eliminating this step in the future may
|
||||
// be easy.
|
||||
// The renderers should just operate on DMA chains, so eliminating this step in the future
|
||||
// may be easy.
|
||||
|
||||
g_gfx_data->dma_copier.set_input_data(data, offset, run_dma_copy);
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ enum GlfwKeyAction {
|
||||
Repeat = GLFW_REPEAT // repeated input on hold e.g. when typing something
|
||||
};
|
||||
|
||||
enum GlfwKeyCustomAxis {
|
||||
CURSOR_X_AXIS = GLFW_GAMEPAD_AXIS_LAST + 1,
|
||||
CURSOR_Y_AXIS = GLFW_GAMEPAD_AXIS_LAST + 2
|
||||
};
|
||||
|
||||
class GLDisplay : public GfxDisplay {
|
||||
public:
|
||||
GLDisplay(GLFWwindow* window, bool is_main);
|
||||
@@ -42,6 +47,9 @@ class GLDisplay : public GfxDisplay {
|
||||
void on_window_pos(GLFWwindow* window, int xpos, int ypos);
|
||||
void on_window_size(GLFWwindow* window, int width, int height);
|
||||
void on_iconify(GLFWwindow* window, int iconified);
|
||||
void on_mouse_key(GLFWwindow* window, int button, int action, int mode);
|
||||
void on_cursor_position(GLFWwindow* window, double xposition, double yposition);
|
||||
void update_cursor_visibility(GLFWwindow* window, bool is_visible);
|
||||
|
||||
private:
|
||||
GLFWwindow* m_window;
|
||||
@@ -52,3 +60,6 @@ class GLDisplay : public GfxDisplay {
|
||||
};
|
||||
|
||||
extern const GfxRendererModule gRendererOpenGL;
|
||||
namespace glfw {
|
||||
static const int NUM_KEYS = GLFW_KEY_LAST + GLFW_MOUSE_BUTTON_LAST + 1;
|
||||
}
|
||||
|
||||
+4
-4
@@ -70,10 +70,10 @@ int scePadRead(int port, int /*slot*/, u8* rdata) {
|
||||
|
||||
cpad->status = 0x70 /* (dualshock2) */ | (20 / 2); /* (dualshock2 data size) */
|
||||
|
||||
cpad->rightx = Gfx::PadAnalogValue(Pad::Analog::Right_X, port);
|
||||
cpad->righty = Gfx::PadAnalogValue(Pad::Analog::Right_Y, port);
|
||||
cpad->leftx = Gfx::PadAnalogValue(Pad::Analog::Left_X, port);
|
||||
cpad->lefty = Gfx::PadAnalogValue(Pad::Analog::Left_Y, port);
|
||||
cpad->rightx = Gfx::PadGetAnalogValue(Pad::Analog::Right_X, port);
|
||||
cpad->righty = Gfx::PadGetAnalogValue(Pad::Analog::Right_Y, port);
|
||||
cpad->leftx = Gfx::PadGetAnalogValue(Pad::Analog::Left_X, port);
|
||||
cpad->lefty = Gfx::PadGetAnalogValue(Pad::Analog::Left_Y, port);
|
||||
|
||||
// pressure sensitivity. ignore for now.
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
|
||||
+265
-78
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "newpad.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
@@ -22,11 +25,12 @@ namespace Pad {
|
||||
********************************
|
||||
*/
|
||||
|
||||
constexpr int NUM_KEYS = GLFW_KEY_LAST + 1;
|
||||
// key-down status of any detected key.
|
||||
bool g_key_status[NUM_KEYS] = {0};
|
||||
bool g_key_status[glfw::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};
|
||||
bool g_buffered_key_status[glfw::NUM_KEYS] = {0};
|
||||
|
||||
float g_key_analogs[CONTROLLER_COUNT][(int)Analog::Max] = {{0}};
|
||||
|
||||
bool g_gamepad_buttons[CONTROLLER_COUNT][(int)Button::Max] = {{0}};
|
||||
float g_gamepad_analogs[CONTROLLER_COUNT][(int)Analog::Max] = {{0}};
|
||||
@@ -44,6 +48,36 @@ u64 input_mode_mod = 0;
|
||||
u64 input_mode_index = 0;
|
||||
MappingInfo g_input_mode_mapping;
|
||||
|
||||
void ClearKey(int key) {
|
||||
if (key < 0 || key > glfw::NUM_KEYS) {
|
||||
lg::warn("ClearKey failed: Attempted to clear invalid key {}", key);
|
||||
return;
|
||||
}
|
||||
|
||||
g_key_status[key] = false;
|
||||
g_buffered_key_status[key] = false;
|
||||
}
|
||||
|
||||
void ClearAnalogAxisValue(MappingInfo& mapping_info, int axis) {
|
||||
for (int pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
for (int analog = 0; analog < (int)Analog::Max; ++analog) {
|
||||
if (mapping_info.keyboard_analog_mapping[pad][analog].axis_id == axis &&
|
||||
mapping_info.keyboard_analog_mapping[pad][analog].mode ==
|
||||
AnalogMappingMode::AnalogInput) {
|
||||
g_key_analogs[pad][analog] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ForceClearAnalogValue() {
|
||||
for (int pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
for (int analog = 0; analog < (int)Analog::Max; ++analog) {
|
||||
g_key_analogs[pad][analog] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ForceClearKeys() {
|
||||
for (auto& key : g_key_status) {
|
||||
key = false;
|
||||
@@ -54,7 +88,7 @@ void ForceClearKeys() {
|
||||
}
|
||||
|
||||
void ClearKeys() {
|
||||
for (int key = 0; key < NUM_KEYS; key++) {
|
||||
for (int key = 0; key < glfw::NUM_KEYS; key++) {
|
||||
g_buffered_key_status[key] = g_key_status[key];
|
||||
}
|
||||
}
|
||||
@@ -77,7 +111,7 @@ void OnKeyPress(int key) {
|
||||
return;
|
||||
}
|
||||
// set absolute key status
|
||||
ASSERT(key < NUM_KEYS);
|
||||
ASSERT(key < glfw::NUM_KEYS);
|
||||
g_key_status[key] = true;
|
||||
// set buffered key status
|
||||
g_buffered_key_status[key] = true;
|
||||
@@ -87,7 +121,7 @@ void OnKeyRelease(int key) {
|
||||
if (input_mode == InputModeStatus::Enabled) {
|
||||
return;
|
||||
}
|
||||
ASSERT(key < NUM_KEYS);
|
||||
ASSERT(key < glfw::NUM_KEYS);
|
||||
g_key_status[key] = false;
|
||||
}
|
||||
|
||||
@@ -98,14 +132,15 @@ void OnKeyRelease(int key) {
|
||||
*/
|
||||
|
||||
static int CheckPadIdx(int pad) {
|
||||
if (pad < 0 || pad > CONTROLLER_COUNT) {
|
||||
if (pad < 0 || pad >= CONTROLLER_COUNT) {
|
||||
lg::error("Invalid pad {}", pad);
|
||||
return -1;
|
||||
}
|
||||
return pad;
|
||||
}
|
||||
|
||||
// returns 1 if button is pressed. returns 0 if invalid or not pressed.
|
||||
// returns 1 if either keyboard or controller button is pressed. Controller button has priority.
|
||||
// returns 0 if invalid or not pressed.
|
||||
int IsPressed(MappingInfo& mapping, Button button, int pad = 0) {
|
||||
if (CheckPadIdx(pad) == -1) {
|
||||
return 0;
|
||||
@@ -114,67 +149,119 @@ int IsPressed(MappingInfo& mapping, Button button, int pad = 0) {
|
||||
if (g_gamepad_buttons[pad][(int)button]) {
|
||||
return 1;
|
||||
}
|
||||
auto key = mapping.pad_mapping[pad][(int)button];
|
||||
|
||||
int key = mapping.keyboard_button_mapping[pad][(int)button];
|
||||
if (key == -1)
|
||||
return 0;
|
||||
auto& keymap = mapping.buffer_mode ? g_buffered_key_status : g_key_status;
|
||||
ASSERT(key < NUM_KEYS);
|
||||
ASSERT(key < glfw::NUM_KEYS);
|
||||
return keymap[key];
|
||||
}
|
||||
|
||||
void SetAnalogAxisValue(MappingInfo& mapping_info, int axis, double value) {
|
||||
const double sensitivity_numerator = Gfx::g_global_settings.target_fps;
|
||||
const double minimum_sensitivity = 1e-4;
|
||||
|
||||
for (int pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
for (int analog = 0; analog < (int)Analog::Max; ++analog) {
|
||||
if (mapping_info.keyboard_analog_mapping[pad][analog].axis_id == axis) {
|
||||
double newValue = value;
|
||||
if (axis == GlfwKeyCustomAxis::CURSOR_X_AXIS) {
|
||||
if (mapping_info.mouse_x_axis_sensitivities[pad] < minimum_sensitivity) {
|
||||
mapping_info.mouse_x_axis_sensitivities[pad] = minimum_sensitivity;
|
||||
}
|
||||
newValue /= (sensitivity_numerator / mapping_info.mouse_x_axis_sensitivities[pad]);
|
||||
} else if (axis == GlfwKeyCustomAxis::CURSOR_Y_AXIS) {
|
||||
if (mapping_info.mouse_y_axis_sensitivities[pad] < minimum_sensitivity) {
|
||||
mapping_info.mouse_y_axis_sensitivities[pad] = minimum_sensitivity;
|
||||
}
|
||||
newValue /= (sensitivity_numerator / mapping_info.mouse_y_axis_sensitivities[pad]);
|
||||
}
|
||||
|
||||
if (newValue > 1.0) {
|
||||
g_key_analogs[pad][analog] = 1.0;
|
||||
} else if (newValue < -1.0) {
|
||||
g_key_analogs[pad][analog] = -1.0;
|
||||
} else if (std::isnan(newValue)) {
|
||||
g_key_analogs[pad][analog] = 0.0;
|
||||
} else {
|
||||
g_key_analogs[pad][analog] = newValue;
|
||||
}
|
||||
|
||||
// Invert logic used here. Left Y axis movement is based on towrds the camera.
|
||||
// In game forward is treated as going away from the camera and backwards is headed towards
|
||||
// the camera.
|
||||
if (axis == GlfwKeyCustomAxis::CURSOR_Y_AXIS) {
|
||||
g_key_analogs[pad][analog] *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAxisValue(MappingInfo& mapping_info) {
|
||||
for (int pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
for (int analog = 0; analog < (int)Analog::Max; ++analog) {
|
||||
if (mapping_info.keyboard_analog_mapping[pad][analog].mode ==
|
||||
AnalogMappingMode::AnalogInput) {
|
||||
continue; // Assumed Set Axis set value already
|
||||
}
|
||||
|
||||
// Invert logic used here. Left Y axis movement is based on towrds the camera.
|
||||
// In game forward is treated as going away from the camera and backwards is headed towards
|
||||
// the camera.
|
||||
double input = 0.0f;
|
||||
if (mapping_info.keyboard_analog_mapping[pad][analog].positive_key > -1 &&
|
||||
mapping_info.keyboard_analog_mapping[pad][analog].positive_key < glfw::NUM_KEYS) {
|
||||
if (analog == static_cast<int>(Analog::Left_Y) ||
|
||||
analog == static_cast<int>(Analog::Right_Y)) {
|
||||
input -=
|
||||
g_buffered_key_status[mapping_info.keyboard_analog_mapping[pad][analog].positive_key];
|
||||
} else {
|
||||
input +=
|
||||
g_buffered_key_status[mapping_info.keyboard_analog_mapping[pad][analog].positive_key];
|
||||
}
|
||||
}
|
||||
if (mapping_info.keyboard_analog_mapping[pad][analog].negative_key > -1 &&
|
||||
mapping_info.keyboard_analog_mapping[pad][analog].negative_key < glfw::NUM_KEYS) {
|
||||
if (analog == static_cast<int>(Analog::Left_Y) ||
|
||||
analog == static_cast<int>(Analog::Right_Y)) {
|
||||
input +=
|
||||
g_buffered_key_status[mapping_info.keyboard_analog_mapping[pad][analog].negative_key];
|
||||
} else {
|
||||
input -=
|
||||
g_buffered_key_status[mapping_info.keyboard_analog_mapping[pad][analog].negative_key];
|
||||
}
|
||||
}
|
||||
g_key_analogs[pad][analog] = input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
int AnalogValue(MappingInfo& /*mapping*/, Analog analog, int pad = 0) {
|
||||
int GetAnalogValue(MappingInfo& /*mapping*/, Analog analog, int pad = 0) {
|
||||
float input = 0.0f;
|
||||
if (CheckPadIdx(pad) == -1) {
|
||||
// Pad out of range, return a stable value
|
||||
return 127;
|
||||
}
|
||||
|
||||
float input = 0.0f;
|
||||
if (pad == 0) {
|
||||
// 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 if (pad == 1) {
|
||||
// these bindings are not sane
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_5] && analog == Analog::Left_Y)
|
||||
input += -1.0f;
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_2] && analog == Analog::Left_Y)
|
||||
input += 1.0f;
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_1] && analog == Analog::Left_X)
|
||||
input += -1.0f;
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_3] && analog == Analog::Left_X)
|
||||
input += 1.0f;
|
||||
|
||||
// these bindings are not sane
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_DIVIDE] && analog == Analog::Right_Y)
|
||||
input += -1.0f;
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_8] && analog == Analog::Right_Y)
|
||||
input += 1.0f;
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_7] && analog == Analog::Right_X)
|
||||
input += -1.0f;
|
||||
if (g_buffered_key_status[GLFW_KEY_KP_9] && analog == Analog::Right_X)
|
||||
input += 1.0f;
|
||||
float controller_input = 0.0f;
|
||||
if (g_gamepads.gamepad_idx[pad] > -1) {
|
||||
controller_input = g_gamepad_analogs[pad][(int)analog];
|
||||
}
|
||||
|
||||
if (input == 0) {
|
||||
input = g_gamepad_analogs[pad][(int)analog];
|
||||
float keyboard_input = g_key_analogs[pad][(int)analog];
|
||||
// Hack. Clearing the buffer immediately can lead to inconsistencies on analog input.
|
||||
// If a mouse is disconnected or can't calculate a new delta it would stay stuck at 1.
|
||||
// Decreasing the values gradually seems like a good comprise.
|
||||
g_key_analogs[pad][(int)analog] *= 0.95;
|
||||
|
||||
if (fabs(controller_input) > fabs(keyboard_input)) {
|
||||
input = controller_input;
|
||||
} else {
|
||||
input = keyboard_input;
|
||||
}
|
||||
|
||||
// GLFW provides float in range -1 to 1, caller expects 0-255
|
||||
@@ -195,15 +282,62 @@ void MapButton(MappingInfo& mapping, Button button, int pad, int key) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapping.pad_mapping[pad][(int)button] = key;
|
||||
if (g_gamepads.gamepad_idx[pad] == -1) {
|
||||
// TODO: Check if other pad is keyboard and if key is already bound
|
||||
mapping.keyboard_button_mapping[pad][(int)button] = key;
|
||||
} else {
|
||||
mapping.controller_button_mapping[pad][(int)button] = key;
|
||||
}
|
||||
}
|
||||
|
||||
void MapAnalog(MappingInfo& mapping, Analog button, int pad, AnalogMappingInfo& analomapping_info) {
|
||||
// check if pad is valid. dont map buttons with invalid pads.
|
||||
if (CheckPadIdx(pad) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_gamepads.gamepad_idx[pad] == -1) {
|
||||
// TODO: Check if other pad is keyboard and if key is already bound
|
||||
mapping.keyboard_analog_mapping[pad][(int)button] = analomapping_info;
|
||||
} else {
|
||||
mapping.controller_analog_mapping[pad][(int)button] = analomapping_info;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
for (int32_t pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
for (int32_t button = 0; button < (int)Pad::Button::Max; ++button) {
|
||||
mapping.controller_button_mapping[pad][button] = -1;
|
||||
mapping.keyboard_button_mapping[pad][button] = -1;
|
||||
}
|
||||
|
||||
for (int32_t analog = 0; analog < (int)Pad::Analog::Max; ++analog) {
|
||||
mapping.controller_analog_mapping[pad][analog] = AnalogMappingInfo();
|
||||
mapping.keyboard_analog_mapping[pad][analog] = AnalogMappingInfo();
|
||||
}
|
||||
}
|
||||
|
||||
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}};
|
||||
|
||||
for (int32_t pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
for (const auto& [button, value] : gamepad_map) {
|
||||
mapping.controller_button_mapping[pad][(int)button] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +346,8 @@ void DefaultMapping(MappingInfo& mapping) {
|
||||
//
|
||||
// Need someway to toggle off -- where do we have access to the game's settings?
|
||||
|
||||
// TODO - What should the second pc default controls be?
|
||||
|
||||
// R1 / L1
|
||||
MapButton(mapping, Button::L1, 0, GLFW_KEY_Q);
|
||||
MapButton(mapping, Button::R1, 0, GLFW_KEY_O);
|
||||
@@ -238,6 +374,31 @@ void DefaultMapping(MappingInfo& mapping) {
|
||||
// l3/r3 for menu
|
||||
MapButton(mapping, Button::L3, 0, GLFW_KEY_COMMA);
|
||||
MapButton(mapping, Button::R3, 0, GLFW_KEY_PERIOD);
|
||||
|
||||
AnalogMappingInfo analomapping_info;
|
||||
|
||||
analomapping_info.positive_key = GLFW_KEY_D;
|
||||
analomapping_info.negative_key = GLFW_KEY_A;
|
||||
MapAnalog(mapping, Analog::Left_X, 0, analomapping_info);
|
||||
|
||||
analomapping_info.positive_key = GLFW_KEY_W;
|
||||
analomapping_info.negative_key = GLFW_KEY_S;
|
||||
MapAnalog(mapping, Analog::Left_Y, 0, analomapping_info);
|
||||
|
||||
analomapping_info.mode = AnalogMappingMode::AnalogInput;
|
||||
analomapping_info.axis_id = GlfwKeyCustomAxis::CURSOR_X_AXIS;
|
||||
MapAnalog(mapping, Analog::Right_X, 0, analomapping_info);
|
||||
|
||||
analomapping_info.axis_id = GlfwKeyCustomAxis::CURSOR_Y_AXIS;
|
||||
MapAnalog(mapping, Analog::Right_Y, 0, analomapping_info);
|
||||
|
||||
const double default_mouse_x_sensitivity = 5.0f;
|
||||
const double default_mouse_y_sensitivity = 2.0f;
|
||||
|
||||
for (int pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
mapping.mouse_x_axis_sensitivities[pad] = default_mouse_x_sensitivity;
|
||||
mapping.mouse_y_axis_sensitivities[pad] = default_mouse_y_sensitivity;
|
||||
}
|
||||
}
|
||||
|
||||
void EnterInputMode() {
|
||||
@@ -315,29 +476,21 @@ void clear_pad(int pad) {
|
||||
for (int i = 0; i < (int)Button::Max; ++i) {
|
||||
g_gamepad_buttons[pad][i] = false;
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < (int)Analog::Max; ++i) {
|
||||
g_gamepad_analogs[pad][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void update_gamepads() {
|
||||
void update_gamepads(MappingInfo& mapping_info) {
|
||||
check_gamepads();
|
||||
UpdateAxisValue(mapping_info);
|
||||
|
||||
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}};
|
||||
if (g_gamepads.gamepad_idx[0] == -1) {
|
||||
for (int pad = 0; pad < CONTROLLER_COUNT; ++pad) {
|
||||
clear_pad(pad);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr std::pair<Analog, int> gamepad_analog_map[] = {
|
||||
{Analog::Left_X, GLFW_GAMEPAD_AXIS_LEFT_X},
|
||||
@@ -345,12 +498,13 @@ void update_gamepads() {
|
||||
{Analog::Right_X, GLFW_GAMEPAD_AXIS_RIGHT_X},
|
||||
{Analog::Right_Y, GLFW_GAMEPAD_AXIS_RIGHT_Y}};
|
||||
|
||||
auto read_pad_state = [gamepad_map, gamepad_analog_map](int pad) {
|
||||
auto read_pad_state = [gamepad_analog_map, mapping_info](int pad) {
|
||||
GLFWgamepadstate state;
|
||||
glfwGetGamepadState(g_gamepads.gamepad_idx[pad], &state);
|
||||
|
||||
for (const auto& [button, idx] : gamepad_map) {
|
||||
g_gamepad_buttons[pad][(int)button] = state.buttons[idx];
|
||||
for (int32_t button = 0; button < (int)Pad::Button::Max; ++button) {
|
||||
int key = mapping_info.controller_button_mapping[pad][button];
|
||||
g_gamepad_buttons[pad][(int)button] = state.buttons[key];
|
||||
}
|
||||
|
||||
g_gamepad_buttons[pad][(int)Button::L2] = state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] > 0;
|
||||
@@ -377,4 +531,37 @@ int rumble(int pad, float slow_motor, float fast_motor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetGamepadState(int pad) {
|
||||
return g_gamepads.gamepad_idx[pad];
|
||||
}
|
||||
|
||||
// The following setters/getters are mainly used for unit tests
|
||||
void SetGamepadState(int pad, int pad_index) {
|
||||
if (CheckPadIdx(pad) != -1) {
|
||||
if (pad_index <= GLFW_JOYSTICK_LAST) {
|
||||
g_gamepads.gamepad_idx[pad] = pad_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool* GetKeyboardInputBuffer() {
|
||||
return g_key_status;
|
||||
}
|
||||
// key-down status of any detected key. this is buffered for the remainder of a frame.
|
||||
bool* GetKeyboardBufferedInputBuffer() {
|
||||
return g_buffered_key_status;
|
||||
}
|
||||
|
||||
float* GetKeyboardInputAnalogBuffer(int pad) {
|
||||
return g_key_analogs[pad];
|
||||
}
|
||||
|
||||
bool* GetControllerInputBuffer(int pad) {
|
||||
return g_gamepad_buttons[pad];
|
||||
}
|
||||
|
||||
float* GetControllerAnalogInputBuffer(int pad) {
|
||||
return g_gamepad_analogs[pad];
|
||||
}
|
||||
|
||||
}; // namespace Pad
|
||||
|
||||
+39
-3
@@ -60,23 +60,48 @@ enum class Button {
|
||||
O = Circle
|
||||
};
|
||||
|
||||
enum class AnalogMappingMode { DigitalInput = 0, AnalogInput = 1 };
|
||||
|
||||
// AnalogMappingInfo allows either button or axes to control analog input(s).
|
||||
// * In Digital Input Mode, uses both positive_key and negative_key as button indices.
|
||||
// * In Analog Input mode, only the positive_key is used.
|
||||
// - The positive_key in Analog Input mode represents an analog axis (i.e
|
||||
// GLFW_GAMEPAD_AXIS_RIGHT_Y)
|
||||
struct AnalogMappingInfo {
|
||||
AnalogMappingMode mode = AnalogMappingMode::DigitalInput;
|
||||
int axis_id = -1;
|
||||
int positive_key = -1;
|
||||
int negative_key = -1;
|
||||
};
|
||||
|
||||
struct MappingInfo {
|
||||
bool debug = true; // debug mode
|
||||
bool buffer_mode = true; // use buffered inputs
|
||||
|
||||
int pad_mapping[CONTROLLER_COUNT][(int)Pad::Button::Max]; // controller button mapping
|
||||
int controller_button_mapping[CONTROLLER_COUNT][(int)Pad::Button::Max];
|
||||
AnalogMappingInfo controller_analog_mapping[CONTROLLER_COUNT][(int)Pad::Analog::Max];
|
||||
|
||||
int keyboard_button_mapping[CONTROLLER_COUNT][(
|
||||
int)Pad::Button::Max]; // Back up in case controller gets disconnected
|
||||
AnalogMappingInfo keyboard_analog_mapping[CONTROLLER_COUNT][(int)Pad::Analog::Max];
|
||||
double mouse_x_axis_sensitivities[CONTROLLER_COUNT];
|
||||
double mouse_y_axis_sensitivities[CONTROLLER_COUNT];
|
||||
// TODO complex button mapping & key macros (e.g. shift+x for l2+r2 press etc.)
|
||||
};
|
||||
|
||||
void OnKeyPress(int key);
|
||||
void OnKeyRelease(int key);
|
||||
void ClearKey(int key);
|
||||
void ForceClearKeys();
|
||||
void ClearKeys();
|
||||
|
||||
void DefaultMapping(MappingInfo& mapping);
|
||||
int IsPressed(MappingInfo& mapping, Button button, int pad);
|
||||
int AnalogValue(MappingInfo& mapping, Analog analog, int pad);
|
||||
int GetAnalogValue(MappingInfo& mapping, Analog analog, int pad);
|
||||
void MapButton(MappingInfo& mapping, Button button, int pad, int key);
|
||||
void MapAnalog(MappingInfo& mapping, Button button, int pad, AnalogMappingInfo& analogMapping);
|
||||
void SetAnalogAxisValue(MappingInfo& mapping, int axis, double value);
|
||||
void ClearAnalogAxisValue(MappingInfo& mapping, int axis);
|
||||
|
||||
// this enum is also in pc-pad-utils.gc
|
||||
enum class InputModeStatus { Disabled, Enabled, Canceled };
|
||||
@@ -90,7 +115,18 @@ u64 input_mode_get_index();
|
||||
void input_mode_pad_set(s64);
|
||||
|
||||
void initialize();
|
||||
void update_gamepads();
|
||||
void update_gamepads(MappingInfo& mapping_info);
|
||||
int rumble(int pad, float slow_motor, float fast_motor);
|
||||
int GetGamepadState(int pad);
|
||||
void ForceClearAnalogValue();
|
||||
void clear_pad(int pad);
|
||||
|
||||
void UpdateAxisValue(MappingInfo& mapping_info);
|
||||
void SetGamepadState(int pad, int pad_index);
|
||||
bool* GetKeyboardInputBuffer();
|
||||
bool* GetKeyboardBufferedInputBuffer();
|
||||
float* GetKeyboardInputAnalogBuffer(int pad);
|
||||
bool* GetControllerInputBuffer(int pad);
|
||||
float* GetControllerAnalogInputBuffer(int pad);
|
||||
|
||||
} // namespace Pad
|
||||
|
||||
@@ -34,6 +34,7 @@ add_executable(goalc-test
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_DataParser.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_DisasmVifDecompile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/decompiler/test_VuDisasm.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/game/test_newpad.cpp
|
||||
${GOALC_TEST_FRAMEWORK_SOURCES}
|
||||
${GOALC_TEST_CASES})
|
||||
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "game/graphics/pipelines/opengl.h"
|
||||
#include "game/system/newpad.h"
|
||||
#include "gtest/gtest.h"
|
||||
//#include "gmock/gmock.h"
|
||||
|
||||
class PeripheralTest : public ::testing::Test {
|
||||
public:
|
||||
PeripheralTest() {
|
||||
Pad::ForceClearKeys();
|
||||
Pad::ForceClearAnalogValue();
|
||||
|
||||
for (int i = 0; i < Pad::CONTROLLER_COUNT; ++i) {
|
||||
Pad::clear_pad(i);
|
||||
Pad::SetGamepadState(i, -1);
|
||||
}
|
||||
Pad::DefaultMapping(mapping_info_);
|
||||
};
|
||||
~PeripheralTest(){};
|
||||
|
||||
protected:
|
||||
Pad::MappingInfo mapping_info_;
|
||||
};
|
||||
|
||||
TEST_F(PeripheralTest, UpdatePad_KeyboardPad_ClearsControllerInputBuffers) {
|
||||
// Arrange
|
||||
bool expected_controller_status = false;
|
||||
|
||||
bool* controller_input_buffer = Pad::GetControllerInputBuffer(0);
|
||||
::memset(controller_input_buffer, true,
|
||||
sizeof(controller_input_buffer[0]) * (int)Pad::Button::Max);
|
||||
|
||||
// Act
|
||||
Pad::update_gamepads(mapping_info_);
|
||||
|
||||
// Assert
|
||||
for (int i = 0; i < (int)Pad::Button::Max; ++i) {
|
||||
EXPECT_EQ(expected_controller_status, controller_input_buffer[i]);
|
||||
}
|
||||
}
|
||||
TEST_F(PeripheralTest, ClearKey_ValidKey_UpdateKeyboardBuffer) {
|
||||
// Arrange
|
||||
int input_key = 127;
|
||||
bool expected_buffer_key_status = false;
|
||||
|
||||
bool* actual_keyboard_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
::memset(actual_keyboard_buffer, true, sizeof(*actual_keyboard_buffer) * glfw::NUM_KEYS);
|
||||
|
||||
// Act
|
||||
Pad::ClearKey(input_key);
|
||||
|
||||
// Assert
|
||||
bool actual_buffer_key_status = actual_keyboard_buffer[input_key];
|
||||
EXPECT_EQ(expected_buffer_key_status, actual_buffer_key_status);
|
||||
}
|
||||
TEST_F(PeripheralTest, ClearKey_InvalidKey_DoNothing) {
|
||||
// Arrange
|
||||
int input_key = glfw::NUM_KEYS + 1;
|
||||
bool expected_buffer_key_status = true;
|
||||
|
||||
bool* actual_keyboard_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
::memset(actual_keyboard_buffer, true, sizeof(*actual_keyboard_buffer) * glfw::NUM_KEYS);
|
||||
|
||||
// Act
|
||||
Pad::ClearKey(input_key);
|
||||
|
||||
// Assert
|
||||
for (int i = 0; i < glfw::NUM_KEYS; ++i) {
|
||||
EXPECT_EQ(expected_buffer_key_status, actual_keyboard_buffer[i]);
|
||||
}
|
||||
}
|
||||
TEST_F(PeripheralTest, SetAnalogAxisValue_NominalAnalogAxisX_SetConvertedValue) {
|
||||
// Arrange
|
||||
float expected_analog_value = 0;
|
||||
std::swap(mapping_info_.controller_analog_mapping[0][(int)Pad::Analog::Left_X],
|
||||
mapping_info_.controller_analog_mapping[0][(int)Pad::Analog::Right_X]);
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_X_AXIS), 100.0);
|
||||
|
||||
// Assert
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(0);
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, keyboard_analog_buffer[(int)Pad::Analog::Left_X]);
|
||||
}
|
||||
TEST_F(PeripheralTest, SetAnalogAxisValue_NominalAnalogAxisY_SetConvertedValue) { // Arrange
|
||||
float expected_analog_value = 0;
|
||||
std::swap(mapping_info_.controller_analog_mapping[0][(int)Pad::Analog::Left_Y],
|
||||
mapping_info_.controller_analog_mapping[0][(int)Pad::Analog::Right_Y]);
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_X_AXIS), 100.0);
|
||||
|
||||
// Assert
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(0);
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, keyboard_analog_buffer[(int)Pad::Analog::Left_Y]);
|
||||
}
|
||||
TEST_F(PeripheralTest, SetAnalogAxisValue_InputLargerThanMaxValue_SetMaxValue) {
|
||||
// Arrange
|
||||
float expected_analog_value = 1;
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_X_AXIS), 100.0);
|
||||
|
||||
// Assert
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(0);
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, keyboard_analog_buffer[(int)Pad::Analog::Right_X]);
|
||||
}
|
||||
TEST_F(PeripheralTest, SetAnalogAxisValue_InputSmallerThanMinValue_SetMinValue) {
|
||||
// Arrange
|
||||
float expected_analog_value = -1;
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_X_AXIS),
|
||||
-100.0);
|
||||
|
||||
// Assert
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(0);
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, keyboard_analog_buffer[(int)Pad::Analog::Right_X]);
|
||||
}
|
||||
TEST_F(PeripheralTest, SetAnalogAxisValue_InputIsNAN_SetZero) {
|
||||
// Arrange
|
||||
float expected_analog_value = 0;
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_X_AXIS),
|
||||
std::nan("1"));
|
||||
|
||||
// Assert
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(0);
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, keyboard_analog_buffer[(int)Pad::Analog::Right_X]);
|
||||
}
|
||||
TEST_F(
|
||||
PeripheralTest,
|
||||
SetAnalogAxisValue_MouseXAxisSensitivityLowerThanMinimumSensitivty_SetMouseSensitivityToMinimum) {
|
||||
// Arrange
|
||||
float expected_x_axis_sensitivity = 1e-4;
|
||||
mapping_info_.mouse_x_axis_sensitivities[0] = 0;
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_X_AXIS), 100);
|
||||
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(expected_x_axis_sensitivity, mapping_info_.mouse_x_axis_sensitivities[0]);
|
||||
}
|
||||
TEST_F(
|
||||
PeripheralTest,
|
||||
SetAnalogAxisValue_MouseYAxisSensitivityLowerThanMinimumSensitivty_SetMouseSensitivityToMinimum) {
|
||||
// Arrange
|
||||
float expected_y_axis_sensitivity = 1e-4;
|
||||
mapping_info_.mouse_y_axis_sensitivities[0] = 0;
|
||||
|
||||
// Act
|
||||
Pad::SetAnalogAxisValue(mapping_info_, static_cast<int>(GlfwKeyCustomAxis::CURSOR_Y_AXIS), 100);
|
||||
|
||||
// Assert
|
||||
EXPECT_FLOAT_EQ(expected_y_axis_sensitivity, mapping_info_.mouse_y_axis_sensitivities[0]);
|
||||
}
|
||||
|
||||
TEST_F(PeripheralTest, UpdateAxisValue_XAxisPositiveKey_IncrementValue) {
|
||||
// Arrange
|
||||
float expected_analog_value = 1.0f;
|
||||
int pad_index = 0;
|
||||
int key = GLFW_KEY_D;
|
||||
bool* keyboard_buffered_key_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
keyboard_buffered_key_buffer[key] = true;
|
||||
|
||||
// Act
|
||||
Pad::UpdateAxisValue(mapping_info_);
|
||||
|
||||
// Arrange
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(pad_index);
|
||||
float actual_analog_value = keyboard_analog_buffer[(int)Pad::Analog::Left_X];
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, actual_analog_value);
|
||||
}
|
||||
TEST_F(PeripheralTest, UpdateAxisValue_YAxisPositiveKey_DecrementValue) {
|
||||
// Arrange
|
||||
float expected_analog_value = -1.0f;
|
||||
int pad_index = 0;
|
||||
int key = GLFW_KEY_W;
|
||||
bool* keyboard_buffered_key_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
keyboard_buffered_key_buffer[key] = true;
|
||||
|
||||
// Act
|
||||
Pad::UpdateAxisValue(mapping_info_);
|
||||
|
||||
// Arrange
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(pad_index);
|
||||
float actual_analog_value = keyboard_analog_buffer[(int)Pad::Analog::Left_Y];
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, actual_analog_value);
|
||||
}
|
||||
TEST_F(PeripheralTest, UpdateAxisValue_XAxisNegativeKey_DecrementValue) {
|
||||
// Arrange
|
||||
int pad_index = 0;
|
||||
float expected_analog_value = -1.0f;
|
||||
|
||||
int key = GLFW_KEY_A;
|
||||
bool* keyboard_buffered_key_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
keyboard_buffered_key_buffer[key] = true;
|
||||
|
||||
// Act
|
||||
Pad::UpdateAxisValue(mapping_info_);
|
||||
|
||||
// Arrange
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(pad_index);
|
||||
float actual_analog_value = keyboard_analog_buffer[(int)Pad::Analog::Left_X];
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, actual_analog_value);
|
||||
}
|
||||
|
||||
TEST_F(PeripheralTest, UpdateAxisValue_RightYAxisPositiveKey_IncrementValue) {
|
||||
// Arrange
|
||||
float expected_analog_value = 1.0f;
|
||||
int pad_index = 0;
|
||||
int key = GLFW_KEY_S;
|
||||
bool* keyboard_buffered_key_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
keyboard_buffered_key_buffer[key] = true;
|
||||
|
||||
// Act
|
||||
Pad::UpdateAxisValue(mapping_info_);
|
||||
|
||||
// Arrange
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(pad_index);
|
||||
float actual_analog_value = keyboard_analog_buffer[(int)Pad::Analog::Left_Y];
|
||||
EXPECT_FLOAT_EQ(expected_analog_value, actual_analog_value);
|
||||
}
|
||||
|
||||
TEST_F(PeripheralTest, GetAnalogValue_InvalidPadId_ReturnsNeutralPosition) {
|
||||
// Arrange
|
||||
int expected_analog_status = 127;
|
||||
|
||||
// Act
|
||||
int actual_analog_status = Pad::GetAnalogValue(mapping_info_, Pad::Analog::Left_X, 2);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(expected_analog_status, actual_analog_status);
|
||||
}
|
||||
TEST_F(PeripheralTest, GetAnalogValue_ControllerPad_ReturnsAnalogValue) {
|
||||
// Arrange
|
||||
int expected_analog_status = 0;
|
||||
|
||||
int pad_index = 0;
|
||||
int controller_index = 0;
|
||||
Pad::SetGamepadState(pad_index, controller_index);
|
||||
|
||||
float* controller_analog_buffer = Pad::GetControllerAnalogInputBuffer(pad_index);
|
||||
controller_analog_buffer[(int)Pad::Analog::Left_X] = -1.0f;
|
||||
|
||||
// Act
|
||||
int actual_analog_status = Pad::GetAnalogValue(mapping_info_, Pad::Analog::Left_X, 0);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(expected_analog_status, actual_analog_status);
|
||||
}
|
||||
TEST_F(PeripheralTest, GetAnalogValue_KeyboardPad_ReturnsAnalogValue) {
|
||||
// Arrange
|
||||
int expected_analog_status = 255;
|
||||
int pad_index = 0;
|
||||
|
||||
float* keyboard_analog_buffer = Pad::GetKeyboardInputAnalogBuffer(pad_index);
|
||||
keyboard_analog_buffer[(int)Pad::Analog::Left_X] = 1.0f;
|
||||
|
||||
// Act
|
||||
int actual_analog_status = Pad::GetAnalogValue(mapping_info_, Pad::Analog::Left_X, 0);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(expected_analog_status, actual_analog_status);
|
||||
}
|
||||
|
||||
TEST_F(PeripheralTest, IsPressed_InvalidPadId_ReturnsFalse) {
|
||||
// Arrange
|
||||
int expected_button_status = 0;
|
||||
|
||||
// Act
|
||||
int actual_button_status = Pad::IsPressed(mapping_info_, Pad::Button::X, 2);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(expected_button_status, actual_button_status);
|
||||
}
|
||||
TEST_F(PeripheralTest, IsPressed_ControllerPad_ReturnsControllerBufferValue) {
|
||||
// Arrange
|
||||
int expected_button_status = 1;
|
||||
|
||||
int pad_index = 0;
|
||||
int controller_index = 0;
|
||||
Pad::SetGamepadState(pad_index, controller_index);
|
||||
|
||||
bool* controller_button_status_buffer = Pad::GetControllerInputBuffer(pad_index);
|
||||
controller_button_status_buffer[(int)Pad::Button::X] = expected_button_status;
|
||||
|
||||
// Act
|
||||
int actual_button_status = Pad::IsPressed(mapping_info_, Pad::Button::X, pad_index);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(expected_button_status, actual_button_status);
|
||||
}
|
||||
TEST_F(PeripheralTest, IsPressed_KeyboardPad_ReturnsKeyboardBufferValue) {
|
||||
// Arrange
|
||||
int expected_button_status = 1;
|
||||
bool* keyboard_buffered_key_status_buffer = Pad::GetKeyboardBufferedInputBuffer();
|
||||
keyboard_buffered_key_status_buffer[GLFW_KEY_SPACE] = expected_button_status;
|
||||
|
||||
// Act
|
||||
int actual_button_status = Pad::IsPressed(mapping_info_, Pad::Button::X, 0);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(expected_button_status, actual_button_status);
|
||||
}
|
||||
|
||||
// TODO: InputModeStatus Tests
|
||||
Reference in New Issue
Block a user