mirror of
https://github.com/open-goal/jak-project
synced 2026-05-30 17:06:23 -04:00
a80cff9a4c
This was just not implemented end to end. There are still two notable issues, one that I can live with, one I need to narrow down eventually: 1. Rebinding confirm buttons with trigger (ie. X) behaviour is not 100% as it should be. I fixed it enough that I can live with it but it's still not proper. The difficulty is that unlike a button it will re-trigger the pressed state on the journey back to neutral (aka unpressed). 2. If you change the bind for the confirm button, then reset your bindings, the next confirm input is eaten. This is unrelated to these changes but I briefly looked into it and was unable to find the root cause.
156 lines
6.4 KiB
C++
156 lines
6.4 KiB
C++
#include "keyboard.h"
|
|
|
|
#include "game/system/hid/sdl_util.h"
|
|
|
|
KeyboardDevice::KeyboardDevice(std::shared_ptr<game_settings::InputSettings> settings) {
|
|
m_settings = settings;
|
|
}
|
|
|
|
// I don't trust SDL's key repeat stuff, do it myself to avoid bug reports...(or cause more)
|
|
bool KeyboardDevice::is_action_already_active(const u32 sdl_keycode) {
|
|
for (const auto& action : m_active_actions) {
|
|
if (action.sdl_keycode == sdl_keycode) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void KeyboardDevice::poll_state(std::shared_ptr<PadData> data) {
|
|
auto& binds = m_settings->keyboard_binds;
|
|
const auto keyboard_state = SDL_GetKeyboardState(NULL);
|
|
const auto keyboard_modifier_state = SDL_GetModState();
|
|
|
|
// Iterate binds, see if there are any new actions we need to track
|
|
// - Normal Buttons
|
|
for (const auto& [sdl_keycode, bind_list] : binds.buttons) {
|
|
for (const auto& bind : bind_list) {
|
|
if (keyboard_state[SDL_GetScancodeFromKey(sdl_keycode)] &&
|
|
bind.modifiers.has_necessary_modifiers(keyboard_modifier_state) &&
|
|
!is_action_already_active(sdl_keycode)) {
|
|
data->button_data.at(bind.pad_data_index) = true; // press the button
|
|
m_active_actions.push_back(
|
|
{sdl_keycode, bind, [](std::shared_ptr<PadData> data, InputBinding bind) {
|
|
data->button_data.at(bind.pad_data_index) = false; // let go of the button
|
|
}});
|
|
}
|
|
}
|
|
}
|
|
// - Analog Buttons
|
|
for (const auto& [sdl_keycode, bind_list] : binds.button_axii) {
|
|
for (const auto& bind : bind_list) {
|
|
if (keyboard_state[SDL_GetScancodeFromKey(sdl_keycode)] &&
|
|
bind.modifiers.has_necessary_modifiers(keyboard_modifier_state) &&
|
|
!is_action_already_active(sdl_keycode)) {
|
|
data->button_data.at(bind.pad_data_index) = true; // press the button
|
|
m_active_actions.push_back(
|
|
{sdl_keycode, bind, [](std::shared_ptr<PadData> data, InputBinding bind) {
|
|
data->button_data.at(bind.pad_data_index) = false; // let go of the button
|
|
}});
|
|
}
|
|
}
|
|
}
|
|
// - Analog Sticks
|
|
for (const auto& [sdl_keycode, bind_list] : binds.analog_axii) {
|
|
for (const auto& bind : bind_list) {
|
|
if (keyboard_state[SDL_GetScancodeFromKey(sdl_keycode)] &&
|
|
bind.modifiers.has_necessary_modifiers(keyboard_modifier_state) &&
|
|
!is_action_already_active(sdl_keycode)) {
|
|
data->analog_data.at(bind.pad_data_index) += bind.minimum_in_range ? -127 : 127;
|
|
data->update_analog_sim_tracker(false);
|
|
m_active_actions.push_back(
|
|
{sdl_keycode, bind, [](std::shared_ptr<PadData> data, InputBinding bind) {
|
|
data->analog_data.at(bind.pad_data_index) += bind.minimum_in_range ? 127 : -127;
|
|
data->update_analog_sim_tracker(true);
|
|
}});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if any previously tracked actions are now invalidated by the new state of the keyboard
|
|
// if so, we'll run their revert code and remove them
|
|
for (auto it = m_active_actions.begin(); it != m_active_actions.end();) {
|
|
// Modifiers are easy, if the action required one and it's not pressed anymore, evict it
|
|
// Alternatively, was the primary key released
|
|
if (!keyboard_state[SDL_GetScancodeFromKey(it->sdl_keycode)] ||
|
|
!it->binding.modifiers.has_necessary_modifiers(keyboard_modifier_state)) {
|
|
it->revert_action(data, it->binding);
|
|
it = m_active_actions.erase(it);
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KeyboardDevice::clear_actions(std::shared_ptr<PadData> data) {
|
|
for (auto it = m_active_actions.begin(); it != m_active_actions.end();) {
|
|
it->revert_action(data, it->binding);
|
|
it = m_active_actions.erase(it);
|
|
}
|
|
}
|
|
|
|
void KeyboardDevice::process_event(const SDL_Event& event,
|
|
const CommandBindingGroups& commands,
|
|
std::shared_ptr<PadData> /*data*/,
|
|
std::optional<InputBindAssignmentMeta>& bind_assignment) {
|
|
if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) {
|
|
const auto key_event = event.key;
|
|
if (m_ignore_key_on_keyup && m_ignore_key_on_keyup.value() == (u32)key_event.keysym.sym &&
|
|
event.type == SDL_KEYUP) {
|
|
m_ignore_key_on_keyup = std::nullopt;
|
|
return;
|
|
}
|
|
|
|
auto& binds = m_settings->keyboard_binds;
|
|
|
|
// Binding re-assignment
|
|
if (bind_assignment) {
|
|
if (bind_assignment->device_type != InputDeviceType::KEYBOARD) {
|
|
return;
|
|
}
|
|
// A normal key down event (a new key was pressed) and it's not a modifier
|
|
if (event.type == SDL_KEYDOWN && !sdl_util::is_modifier_key(key_event.keysym.sym)) {
|
|
if (bind_assignment->for_analog) {
|
|
m_ignore_key_on_keyup = key_event.keysym.sym;
|
|
binds.assign_analog_bind(key_event.keysym.sym, bind_assignment.value(),
|
|
InputModifiers(key_event.keysym.mod));
|
|
} else {
|
|
binds.assign_button_bind(key_event.keysym.sym, bind_assignment.value(), false,
|
|
InputModifiers(key_event.keysym.mod));
|
|
}
|
|
} else if (event.type == SDL_KEYUP) {
|
|
// modifiers are instead inspected on a KEYUP, however if it's one of the keys
|
|
// for triggering the binding assignment, and it's the first time we've seen it -- we ignore
|
|
// it
|
|
if (!bind_assignment->seen_keyboard_confirm_up) {
|
|
for (const auto& confirm_bind : bind_assignment->keyboard_confirmation_binds) {
|
|
if (confirm_bind.sdl_idx == key_event.keysym.sym) {
|
|
bind_assignment->seen_keyboard_confirm_up = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// otherwise, set the bind
|
|
if (bind_assignment->for_analog) {
|
|
binds.assign_analog_bind(key_event.keysym.sym, bind_assignment.value(),
|
|
InputModifiers(key_event.keysym.mod));
|
|
} else {
|
|
binds.assign_button_bind(key_event.keysym.sym, bind_assignment.value(), false,
|
|
InputModifiers(key_event.keysym.mod));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Check for commands
|
|
if (event.type == SDL_KEYDOWN &&
|
|
commands.keyboard_binds.find(key_event.keysym.sym) != commands.keyboard_binds.end()) {
|
|
for (const auto& command : commands.keyboard_binds.at(key_event.keysym.sym)) {
|
|
if (command.modifiers.has_necessary_modifiers(key_event.keysym.mod)) {
|
|
command.command();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|