mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 00:42:48 +00:00
Apply recent changes from kbm-only
This commit is contained in:
parent
c46edf1c39
commit
20cdbf5988
@ -808,6 +808,8 @@ set(INPUT src/input/controller.cpp
|
||||
src/input/controller.h
|
||||
src/input/input_handler.cpp
|
||||
src/input/input_handler.h
|
||||
src/input/input_mouse.cpp
|
||||
src/input/input_mouse.h
|
||||
)
|
||||
|
||||
set(EMULATOR src/emulator.cpp
|
||||
|
@ -148,7 +148,7 @@ bool ProcessEvent(SDL_Event* event) {
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
|
||||
const auto& io = GetIO();
|
||||
return io.WantCaptureMouse && io.Ctx->NavWindow != nullptr &&
|
||||
io.Ctx->NavWindow->ID != dock_id;
|
||||
(io.Ctx->NavWindow->Flags & ImGuiWindowFlags_NoNav) == 0;
|
||||
}
|
||||
case SDL_EVENT_TEXT_INPUT:
|
||||
case SDL_EVENT_KEY_DOWN: {
|
||||
|
@ -3,14 +3,17 @@
|
||||
|
||||
#include "input_handler.h"
|
||||
|
||||
#include "fstream"
|
||||
#include "iostream"
|
||||
#include "list"
|
||||
#include "map"
|
||||
#include "sstream"
|
||||
#include "string"
|
||||
#include "unordered_map"
|
||||
#include "vector"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
@ -21,6 +24,7 @@
|
||||
#include "common/path_util.h"
|
||||
#include "common/version.h"
|
||||
#include "input/controller.h"
|
||||
#include "input/input_mouse.h"
|
||||
|
||||
namespace Input {
|
||||
/*
|
||||
@ -50,18 +54,13 @@ Joystick halfmode
|
||||
Don't be an idiot and test only the changed part expecting everything else to not be broken
|
||||
*/
|
||||
|
||||
// Flags and values for varying purposes
|
||||
// todo: can we change these?
|
||||
int mouse_joystick_binding = 0;
|
||||
float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250;
|
||||
Uint32 mouse_polling_id = 0;
|
||||
bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false;
|
||||
bool leftjoystick_halfmode = false, rightjoystick_halfmode = false;
|
||||
|
||||
std::list<std::pair<u32, bool>> pressed_keys;
|
||||
std::list<u32> toggled_keys;
|
||||
std::list<BindingConnection> connections = std::list<BindingConnection>();
|
||||
std::list<std::pair<InputEvent, bool>> pressed_keys;
|
||||
std::list<InputID> toggled_keys;
|
||||
static std::vector<BindingConnection> connections;
|
||||
|
||||
ControllerOutput output_array[] = {
|
||||
auto output_array = std::array{
|
||||
// Important: these have to be the first, or else they will update in the wrong order
|
||||
ControllerOutput((OrbisPadButtonDataOffset)LEFTJOYSTICK_HALFMODE),
|
||||
ControllerOutput((OrbisPadButtonDataOffset)RIGHTJOYSTICK_HALFMODE),
|
||||
@ -91,15 +90,9 @@ ControllerOutput output_array[] = {
|
||||
ControllerOutput(OrbisPadButtonDataOffset::None, Axis::TriggerLeft),
|
||||
ControllerOutput(OrbisPadButtonDataOffset::None, Axis::TriggerRight),
|
||||
|
||||
// the "sorry, you gave an incorrect value, now we bind it to nothing" output
|
||||
ControllerOutput(OrbisPadButtonDataOffset::None, Axis::AxisMax),
|
||||
};
|
||||
|
||||
// We had to go through 3 files of indirection just to update a flag
|
||||
void ToggleMouseEnabled() {
|
||||
mouse_enabled ^= true;
|
||||
}
|
||||
|
||||
// parsing related functions
|
||||
u32 GetAxisInputId(AxisMapping a) {
|
||||
// LOG_INFO(Input, "Parsing an axis...");
|
||||
@ -156,76 +149,39 @@ u32 GetControllerButtonInputId(u32 cbutton) {
|
||||
|
||||
// syntax: 'name, name,name' or 'name,name' or 'name'
|
||||
InputBinding GetBindingFromString(std::string& line) {
|
||||
u32 key1 = 0, key2 = 0, key3 = 0;
|
||||
|
||||
// Split the string by commas
|
||||
std::vector<std::string> tokens;
|
||||
std::stringstream ss(line);
|
||||
std::string token;
|
||||
|
||||
while (std::getline(ss, token, ',')) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
std::array<InputID, 3> keys = {InputID(), InputID(), InputID()};
|
||||
|
||||
// Check and process tokens
|
||||
for (const auto& t : tokens) {
|
||||
for (const auto token : std::views::split(line, ',')) { // Split by comma
|
||||
const std::string t(token.begin(), token.end());
|
||||
InputID input;
|
||||
|
||||
if (string_to_keyboard_key_map.find(t) != string_to_keyboard_key_map.end()) {
|
||||
// Map to keyboard key
|
||||
u32 key_id = string_to_keyboard_key_map.at(t);
|
||||
if (!key1)
|
||||
key1 = key_id;
|
||||
else if (!key2)
|
||||
key2 = key_id;
|
||||
else if (!key3)
|
||||
key3 = key_id;
|
||||
input = InputID(InputType::KeyboardMouse, string_to_keyboard_key_map.at(t));
|
||||
} else if (string_to_axis_map.find(t) != string_to_axis_map.end()) {
|
||||
// Map to axis input ID
|
||||
u32 axis_id = GetAxisInputId(string_to_axis_map.at(t));
|
||||
if (axis_id == (u32)-1) {
|
||||
return InputBinding(0, 0, 0);
|
||||
}
|
||||
if (!key1)
|
||||
key1 = axis_id;
|
||||
else if (!key2)
|
||||
key2 = axis_id;
|
||||
else if (!key3)
|
||||
key3 = axis_id;
|
||||
input = InputID(InputType::Axis, (u32)string_to_axis_map.at(t).axis);
|
||||
} else if (string_to_cbutton_map.find(t) != string_to_cbutton_map.end()) {
|
||||
// Map to controller button input ID
|
||||
u32 cbutton_id = GetControllerButtonInputId((u32)string_to_cbutton_map.at(t));
|
||||
if (cbutton_id == (u32)-1) {
|
||||
return InputBinding(0, 0, 0);
|
||||
}
|
||||
if (!key1)
|
||||
key1 = cbutton_id;
|
||||
else if (!key2)
|
||||
key2 = cbutton_id;
|
||||
else if (!key3)
|
||||
key3 = cbutton_id;
|
||||
input = InputID(InputType::Controller, (u32)string_to_cbutton_map.at(t));
|
||||
} else {
|
||||
// Invalid token found; return default binding
|
||||
return InputBinding(0, 0, 0);
|
||||
LOG_DEBUG(Input, "Invalid token found: {}", t);
|
||||
return InputBinding();
|
||||
}
|
||||
|
||||
// Assign to the first available slot
|
||||
for (auto& key : keys) {
|
||||
if (!key.IsValid()) {
|
||||
key = input;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return InputBinding(key1, key2, key3);
|
||||
}
|
||||
|
||||
// function that takes a controlleroutput, and returns the array's corresponding element's pointer
|
||||
ControllerOutput* GetOutputPointer(const ControllerOutput& parsed) {
|
||||
// i wonder how long until someone notices this or I get rid of it
|
||||
int i = 0;
|
||||
for (; i[output_array] != ControllerOutput(OrbisPadButtonDataOffset::None, Axis::AxisMax);
|
||||
i++) {
|
||||
if (i[output_array] == parsed) {
|
||||
return &output_array[i];
|
||||
}
|
||||
}
|
||||
return &output_array[i];
|
||||
LOG_DEBUG(Input, "Parsed line: {} {} {}", keys[0].ToString(), keys[1].ToString(),
|
||||
keys[2].ToString());
|
||||
return InputBinding(keys[0], keys[1], keys[2]);
|
||||
}
|
||||
|
||||
void ParseInputConfig(const std::string game_id = "") {
|
||||
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(game_id);
|
||||
|
||||
// todo: change usages of this to GetFoolproofKbmConfigFile (in the gui)
|
||||
@ -236,17 +192,21 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
// we reset these here so in case the user fucks up or doesn't include this,
|
||||
// we can fall back to default
|
||||
connections.clear();
|
||||
mouse_deadzone_offset = 0.5;
|
||||
mouse_speed = 1;
|
||||
mouse_speed_offset = 0.125;
|
||||
float mouse_deadzone_offset = 0.5;
|
||||
float mouse_speed = 1;
|
||||
float mouse_speed_offset = 0.125;
|
||||
int lineCount = 0;
|
||||
|
||||
std::ifstream file(config_file);
|
||||
std::string line = "";
|
||||
while (std::getline(file, line)) {
|
||||
lineCount++;
|
||||
|
||||
// Strip the ; and whitespace
|
||||
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
|
||||
line.erase(std::remove_if(line.begin(), line.end(),
|
||||
[](unsigned char c) { return std::isspace(c); }),
|
||||
line.end());
|
||||
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
@ -255,15 +215,14 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
if (comment_pos != std::string::npos) {
|
||||
line = line.substr(0, comment_pos);
|
||||
}
|
||||
|
||||
// Remove trailing semicolon
|
||||
if (!line.empty() && line[line.length() - 1] == ';') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split the line by '='
|
||||
std::size_t equal_pos = line.find('=');
|
||||
if (equal_pos == std::string::npos) {
|
||||
@ -278,11 +237,12 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
|
||||
if (output_string == "mouse_to_joystick") {
|
||||
if (input_string == "left") {
|
||||
mouse_joystick_binding = 1;
|
||||
SetMouseToJoystick(1);
|
||||
} else if (input_string == "right") {
|
||||
mouse_joystick_binding = 2;
|
||||
SetMouseToJoystick(2);
|
||||
} else {
|
||||
mouse_joystick_binding = 0; // default to 'none' or invalid
|
||||
LOG_WARNING(Input, "Invalid argument for mouse-to-joystick binding");
|
||||
SetMouseToJoystick(0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -297,10 +257,10 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
ControllerOutput* toggle_out =
|
||||
GetOutputPointer(ControllerOutput((OrbisPadButtonDataOffset)KEY_TOGGLE));
|
||||
BindingConnection toggle_connection =
|
||||
BindingConnection(InputBinding(toggle_keys.key2), toggle_out, toggle_keys.key3);
|
||||
ControllerOutput* toggle_out = &*std::ranges::find(
|
||||
output_array, ControllerOutput((OrbisPadButtonDataOffset)KEY_TOGGLE));
|
||||
BindingConnection toggle_connection = BindingConnection(
|
||||
InputBinding(toggle_keys.keys[0]), toggle_out, 0, toggle_keys.keys[1]);
|
||||
connections.insert(connections.end(), toggle_connection);
|
||||
continue;
|
||||
}
|
||||
@ -322,7 +282,7 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
|
||||
// normal cases
|
||||
InputBinding binding = GetBindingFromString(input_string);
|
||||
BindingConnection connection(0, nullptr);
|
||||
BindingConnection connection(InputID(), nullptr);
|
||||
auto button_it = string_to_cbutton_map.find(output_string);
|
||||
auto axis_it = string_to_axis_map.find(output_string);
|
||||
|
||||
@ -332,37 +292,40 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
continue;
|
||||
}
|
||||
if (button_it != string_to_cbutton_map.end()) {
|
||||
connection =
|
||||
BindingConnection(binding, GetOutputPointer(ControllerOutput(button_it->second)));
|
||||
connection = BindingConnection(
|
||||
binding, &*std::ranges::find(output_array, ControllerOutput(button_it->second)));
|
||||
connections.insert(connections.end(), connection);
|
||||
|
||||
} else if (axis_it != string_to_axis_map.end()) {
|
||||
int value_to_set = (binding.key3 & 0x80000000) != 0 ? 0
|
||||
int value_to_set = binding.keys[2].type == InputType::Axis ? 0
|
||||
: (axis_it->second.axis == Axis::TriggerLeft ||
|
||||
axis_it->second.axis == Axis::TriggerRight)
|
||||
? 127
|
||||
: axis_it->second.value;
|
||||
connection =
|
||||
BindingConnection(binding,
|
||||
GetOutputPointer(ControllerOutput(OrbisPadButtonDataOffset::None,
|
||||
axis_it->second.axis)),
|
||||
value_to_set);
|
||||
connection = BindingConnection(
|
||||
binding,
|
||||
&*std::ranges::find(output_array, ControllerOutput(OrbisPadButtonDataOffset::None,
|
||||
axis_it->second.axis)),
|
||||
value_to_set);
|
||||
connections.insert(connections.end(), connection);
|
||||
} else {
|
||||
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
continue;
|
||||
}
|
||||
// LOG_INFO(Input, "Succesfully parsed line {}", lineCount);
|
||||
LOG_DEBUG(Input, "Succesfully parsed line {}", lineCount);
|
||||
}
|
||||
file.close();
|
||||
connections.sort();
|
||||
std::sort(connections.begin(), connections.end());
|
||||
for (auto& c : connections) {
|
||||
LOG_DEBUG(Input, "Binding: {}", c.binding.ToString());
|
||||
}
|
||||
LOG_DEBUG(Input, "Done parsing the input config!");
|
||||
}
|
||||
|
||||
u32 GetMouseWheelEvent(const SDL_Event& event) {
|
||||
if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) {
|
||||
LOG_DEBUG(Input, "Something went wrong with wheel input parsing!");
|
||||
LOG_WARNING(Input, "Something went wrong with wheel input parsing!");
|
||||
return (u32)-1;
|
||||
}
|
||||
if (event.wheel.y > 0) {
|
||||
@ -377,31 +340,28 @@ u32 GetMouseWheelEvent(const SDL_Event& event) {
|
||||
return (u32)-1;
|
||||
}
|
||||
|
||||
u32 InputBinding::GetInputIDFromEvent(const SDL_Event& e) {
|
||||
InputEvent InputBinding::GetInputEventFromSDLEvent(const SDL_Event& e) {
|
||||
int value_mask;
|
||||
switch (e.type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
return e.key.key;
|
||||
return InputEvent(InputType::KeyboardMouse, e.key.key, e.type == SDL_EVENT_KEY_DOWN, 0);
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
return (u32)e.button.button;
|
||||
return InputEvent(InputType::KeyboardMouse, e.button.button,
|
||||
e.type == SDL_EVENT_MOUSE_BUTTON_DOWN, 0);
|
||||
case SDL_EVENT_MOUSE_WHEEL:
|
||||
case SDL_EVENT_MOUSE_WHEEL_OFF:
|
||||
return GetMouseWheelEvent(e);
|
||||
return InputEvent(InputType::KeyboardMouse, GetMouseWheelEvent(e),
|
||||
e.type == SDL_EVENT_MOUSE_WHEEL, 0);
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||
return (u32)e.gbutton.button + 0x10000000; // I believe this range is unused
|
||||
return InputEvent(InputType::Controller, e.gbutton.button,
|
||||
e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN, 0);
|
||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||
// todo: somehow put this value into the correct connection
|
||||
// solution 1: add it to the keycode as a 0x0FF00000 (a bit hacky but works I guess?)
|
||||
// I guess in software developement, there really is nothing more permanent than a temporary
|
||||
// solution
|
||||
value_mask = (u32)((e.gaxis.value / 256 + 128) << 20); // +-32000 to +-128 to 0-255
|
||||
return (u32)e.gaxis.axis + 0x80000000 +
|
||||
value_mask; // they are pushed to the end of the sorted array
|
||||
return InputEvent(InputType::Controller, e.gaxis.axis, true, (s8)(e.gaxis.value / 256));
|
||||
default:
|
||||
return (u32)-1;
|
||||
return InputEvent(InputType::Count, (u32)-1, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,18 +370,18 @@ void ControllerOutput::SetControllerOutputController(GameController* c) {
|
||||
ControllerOutput::controller = c;
|
||||
}
|
||||
|
||||
void ToggleKeyInList(u32 key) {
|
||||
if ((key & 0x80000000) != 0) {
|
||||
void ToggleKeyInList(InputID input) {
|
||||
if (input.type == InputType::Axis) {
|
||||
LOG_ERROR(Input, "Toggling analog inputs is not supported!");
|
||||
return;
|
||||
}
|
||||
auto it = std::find(toggled_keys.begin(), toggled_keys.end(), key);
|
||||
auto it = std::find(toggled_keys.begin(), toggled_keys.end(), input);
|
||||
if (it == toggled_keys.end()) {
|
||||
toggled_keys.insert(toggled_keys.end(), key);
|
||||
LOG_DEBUG(Input, "Added {} to toggled keys", key);
|
||||
toggled_keys.insert(toggled_keys.end(), input);
|
||||
LOG_DEBUG(Input, "Added {} to toggled keys", input.ToString());
|
||||
} else {
|
||||
toggled_keys.erase(it);
|
||||
LOG_DEBUG(Input, "Removed {} from toggled keys", key);
|
||||
LOG_DEBUG(Input, "Removed {} from toggled keys", input.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,14 +390,19 @@ void ControllerOutput::ResetUpdate() {
|
||||
new_button_state = false;
|
||||
new_param = 0;
|
||||
}
|
||||
void ControllerOutput::AddUpdate(bool pressed, bool analog, u32 param) {
|
||||
void ControllerOutput::AddUpdate(InputEvent event) {
|
||||
state_changed = true;
|
||||
if (button != OrbisPadButtonDataOffset::None) {
|
||||
if (analog) {
|
||||
new_button_state |= abs((s32)param) > 0x40;
|
||||
if ((u32)button == KEY_TOGGLE) {
|
||||
if (event.active) {
|
||||
LOG_DEBUG(Input, "Toggling a button...");
|
||||
ToggleKeyInList(event.input); // todo: fix key toggle
|
||||
}
|
||||
} else if (button != OrbisPadButtonDataOffset::None) {
|
||||
if (event.input.type == InputType::Axis) {
|
||||
new_button_state |= abs((s32)event.axis_value) > 0x40;
|
||||
} else {
|
||||
new_button_state |= pressed;
|
||||
new_param = param;
|
||||
new_button_state |= event.active;
|
||||
new_param = event.axis_value;
|
||||
}
|
||||
|
||||
} else if (axis != Axis::AxisMax) {
|
||||
@ -446,17 +411,18 @@ void ControllerOutput::AddUpdate(bool pressed, bool analog, u32 param) {
|
||||
case Axis::TriggerRight:
|
||||
// if it's a button input, then we know the value to set, so the param is 0.
|
||||
// if it's an analog input, then the param isn't 0
|
||||
// warning: doesn't work yet
|
||||
new_param = SDL_clamp((pressed ? (s32)param : 0) + new_param, 0, 127);
|
||||
new_param = (event.active ? (s32)event.axis_value : 0) + new_param;
|
||||
break;
|
||||
default:
|
||||
// todo: do the same as above
|
||||
new_param = SDL_clamp((pressed ? (s32)param : 0) + new_param, -127, 127);
|
||||
new_param = (event.active ? (s32)event.axis_value : 0) + new_param;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ControllerOutput::FinalizeUpdate() {
|
||||
if (!state_changed) {
|
||||
// return;
|
||||
}
|
||||
old_button_state = new_button_state;
|
||||
old_param = new_param;
|
||||
float touchpad_x = 0;
|
||||
@ -475,12 +441,10 @@ void ControllerOutput::FinalizeUpdate() {
|
||||
case RIGHTJOYSTICK_HALFMODE:
|
||||
rightjoystick_halfmode = new_button_state;
|
||||
break;
|
||||
case KEY_TOGGLE:
|
||||
if (new_button_state) {
|
||||
// LOG_DEBUG(Input, "Toggling a button...");
|
||||
ToggleKeyInList(new_param);
|
||||
}
|
||||
break;
|
||||
// KEY_TOGGLE isn't handled here anymore, as this function doesn't have the necessary data
|
||||
// to do it, and it would be inconvenient to force it here, when AddUpdate does the job just
|
||||
// fine, and a toggle doesn't have to checked against every input that's bound to it, it's
|
||||
// enough that one is pressed
|
||||
default: // is a normal key (hopefully)
|
||||
controller->CheckButton(0, (OrbisPadButtonDataOffset)button, new_button_state);
|
||||
break;
|
||||
@ -514,44 +478,43 @@ void ControllerOutput::FinalizeUpdate() {
|
||||
|
||||
// Updates the list of pressed keys with the given input.
|
||||
// Returns whether the list was updated or not.
|
||||
bool UpdatePressedKeys(u32 value, bool is_pressed) {
|
||||
bool UpdatePressedKeys(InputEvent event) {
|
||||
// Skip invalid inputs
|
||||
if (value == (u32)-1) {
|
||||
InputID input = event.input;
|
||||
if (input.sdl_id == (u32)-1) {
|
||||
return false;
|
||||
}
|
||||
if ((value & 0x80000000) != 0) {
|
||||
if (input.type == InputType::Axis) {
|
||||
// analog input, it gets added when it first sends an event,
|
||||
// and from there, it only changes the parameter
|
||||
// reverse iterate until we get out of the 0x8000000 range, if found,
|
||||
// update the parameter, if not, add it to the end
|
||||
u32 value_to_search = value & 0xF00FFFFF;
|
||||
for (auto& it = --pressed_keys.end(); (it->first & 0x80000000) != 0; it--) {
|
||||
if ((it->first & 0xF00FFFFF) == value_to_search) {
|
||||
it->first = value;
|
||||
// LOG_DEBUG(Input, "New value for {:X}: {:x}", value, value);
|
||||
return true;
|
||||
}
|
||||
const auto& it = std::find_if(
|
||||
pressed_keys.begin(), pressed_keys.end(),
|
||||
[input](const std::pair<InputEvent, bool>& e) { return e.first.input == input; });
|
||||
if (it == pressed_keys.end()) {
|
||||
pressed_keys.push_back({event, false});
|
||||
} else {
|
||||
it->first.axis_value = event.axis_value;
|
||||
}
|
||||
// LOG_DEBUG(Input, "Input activated for the first time, adding it to the list");
|
||||
pressed_keys.insert(pressed_keys.end(), {value, false});
|
||||
return true;
|
||||
}
|
||||
if (is_pressed) {
|
||||
if (event.active) {
|
||||
// Find the correct position for insertion to maintain order
|
||||
auto it =
|
||||
std::lower_bound(pressed_keys.begin(), pressed_keys.end(), value,
|
||||
[](const std::pair<u32, bool>& pk, u32 v) { return pk.first < v; });
|
||||
auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), input,
|
||||
[](const std::pair<InputEvent, bool>& e, InputID i) {
|
||||
return e.first.input.type <= i.type &&
|
||||
e.first.input.sdl_id < i.sdl_id;
|
||||
});
|
||||
|
||||
// Insert only if 'value' is not already in the list
|
||||
if (it == pressed_keys.end() || it->first != value) {
|
||||
pressed_keys.insert(it, {value, false});
|
||||
if (it == pressed_keys.end() || it->first.input != input) {
|
||||
pressed_keys.insert(it, {event, false});
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Remove 'value' from the list if it's not pressed
|
||||
auto it =
|
||||
std::find_if(pressed_keys.begin(), pressed_keys.end(),
|
||||
[value](const std::pair<u32, bool>& pk) { return pk.first == value; });
|
||||
auto it = std::find_if(
|
||||
pressed_keys.begin(), pressed_keys.end(),
|
||||
[input](const std::pair<InputEvent, bool>& e) { return e.first.input == input; });
|
||||
if (it != pressed_keys.end()) {
|
||||
pressed_keys.erase(it);
|
||||
return true;
|
||||
@ -559,17 +522,28 @@ bool UpdatePressedKeys(u32 value, bool is_pressed) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Check if a given binding's all keys are currently active.
|
||||
// For now it also extracts the analog inputs' parameters.
|
||||
void IsInputActive(BindingConnection& connection, bool& active, bool& analog) {
|
||||
// Check if the binding's all keys are currently active.
|
||||
// It also extracts the analog inputs' parameters, and updates the input hierarchy flags.
|
||||
InputEvent BindingConnection::ProcessBinding() {
|
||||
// the last key is always set (if the connection isn't empty),
|
||||
// and the analog inputs are always the last one due to how they are sorted,
|
||||
// so this signifies whether or not the input is analog
|
||||
InputEvent event = InputEvent(binding.keys[3]);
|
||||
if (pressed_keys.empty()) {
|
||||
active = false;
|
||||
return;
|
||||
return event;
|
||||
}
|
||||
InputBinding i = connection.binding;
|
||||
// Extract keys from InputBinding and ignore unused (0) or toggled keys
|
||||
std::list<u32> input_keys = {i.key1, i.key2, i.key3};
|
||||
input_keys.remove(0);
|
||||
if (event.input.type != InputType::Axis) {
|
||||
// for button inputs
|
||||
event.axis_value = axis_param;
|
||||
}
|
||||
// it's a bit scuffed, but if the output is a toggle, then we put the key here
|
||||
if ((u32)output->button == KEY_TOGGLE) {
|
||||
event.input = toggle;
|
||||
}
|
||||
|
||||
// Extract keys from InputBinding and ignore unused or toggled keys
|
||||
std::list<InputID> input_keys = {binding.keys[0], binding.keys[1], binding.keys[2]};
|
||||
input_keys.remove(InputID());
|
||||
for (auto key = input_keys.begin(); key != input_keys.end();) {
|
||||
if (std::find(toggled_keys.begin(), toggled_keys.end(), *key) != toggled_keys.end()) {
|
||||
key = input_keys.erase(key); // Use the returned iterator
|
||||
@ -579,8 +553,8 @@ void IsInputActive(BindingConnection& connection, bool& active, bool& analog) {
|
||||
}
|
||||
if (input_keys.empty()) {
|
||||
LOG_DEBUG(Input, "No actual inputs to check, returning true");
|
||||
active = true;
|
||||
return;
|
||||
event.active = true;
|
||||
return event;
|
||||
}
|
||||
|
||||
// Iterator for pressed_keys, starting from the beginning
|
||||
@ -590,119 +564,53 @@ void IsInputActive(BindingConnection& connection, bool& active, bool& analog) {
|
||||
std::list<bool*> flags_to_set;
|
||||
|
||||
// Check if all keys in input_keys are active
|
||||
for (u32 key : input_keys) {
|
||||
for (InputID key : input_keys) {
|
||||
bool key_found = false;
|
||||
|
||||
// Search for the current key in pressed_keys starting from the last checked position
|
||||
while (pressed_it != pressed_keys.end() && (pressed_it->first & 0x80000000) == 0) {
|
||||
if (pressed_it->first == key) {
|
||||
|
||||
while (pressed_it != pressed_keys.end()) {
|
||||
if (pressed_it->first.input == key && pressed_it->second == false) {
|
||||
key_found = true;
|
||||
flags_to_set.push_back(&pressed_it->second);
|
||||
|
||||
++pressed_it; // Move to the next key in pressed_keys
|
||||
if (pressed_it->first.input.type == InputType::Axis) {
|
||||
event.axis_value = pressed_it->first.axis_value;
|
||||
}
|
||||
++pressed_it;
|
||||
break;
|
||||
}
|
||||
++pressed_it;
|
||||
}
|
||||
if (!key_found && (key & 0x80000000) != 0) {
|
||||
// reverse iterate over the analog inputs, as they can't be sorted
|
||||
auto& rev_it = --pressed_keys.end();
|
||||
for (auto rev_it = --pressed_keys.end(); (rev_it->first & 0x80000000) != 0; rev_it--) {
|
||||
if ((rev_it->first & 0xF00FFFFF) == (key & 0xF00FFFFF)) {
|
||||
connection.parameter = (u32)((s32)((rev_it->first & 0x0FF00000) >> 20) - 128);
|
||||
// LOG_DEBUG(Input, "Extracted the following param: {:X} from {:X}",
|
||||
// (s32)connection.parameter, rev_it->first);
|
||||
key_found = true;
|
||||
analog = true;
|
||||
flags_to_set.push_back(&rev_it->second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!key_found) {
|
||||
return;
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_fully_blocked = true;
|
||||
for (bool* flag : flags_to_set) {
|
||||
is_fully_blocked &= *flag;
|
||||
}
|
||||
if (is_fully_blocked) {
|
||||
return;
|
||||
}
|
||||
for (bool* flag : flags_to_set) {
|
||||
*flag = true;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Input, "Input found: {}", i.ToString());
|
||||
active = true;
|
||||
return; // All keys are active
|
||||
LOG_DEBUG(Input, "Input found: {}", binding.ToString());
|
||||
event.active = true;
|
||||
return event; // All keys are active
|
||||
}
|
||||
|
||||
void ActivateOutputsFromInputs() {
|
||||
// LOG_DEBUG(Input, "Start of an input frame...");
|
||||
// Reset values and flags
|
||||
for (auto& it : pressed_keys) {
|
||||
it.second = false;
|
||||
}
|
||||
|
||||
// this is the cleanest looking code I've ever written, too bad it is not working
|
||||
// (i left the last part in by accident, then it turnd out to still be true even after I thought
|
||||
// everything is good) (but now it really should be fine)
|
||||
for (auto& it : output_array) {
|
||||
it.ResetUpdate();
|
||||
}
|
||||
|
||||
// Iterate over all inputs, and update their respecive outputs accordingly
|
||||
for (auto& it : connections) {
|
||||
bool active = false, analog_input_detected = false;
|
||||
IsInputActive(it, active, analog_input_detected);
|
||||
it.output->AddUpdate(active, analog_input_detected, it.parameter);
|
||||
it.output->AddUpdate(it.ProcessBinding());
|
||||
}
|
||||
|
||||
// Update all outputs
|
||||
for (auto& it : output_array) {
|
||||
it.FinalizeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMouse(GameController* controller) {
|
||||
if (!mouse_enabled)
|
||||
return;
|
||||
Axis axis_x, axis_y;
|
||||
switch (mouse_joystick_binding) {
|
||||
case 1:
|
||||
axis_x = Axis::LeftX;
|
||||
axis_y = Axis::LeftY;
|
||||
break;
|
||||
case 2:
|
||||
axis_x = Axis::RightX;
|
||||
axis_y = Axis::RightY;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
return; // no update needed
|
||||
}
|
||||
|
||||
float d_x = 0, d_y = 0;
|
||||
SDL_GetRelativeMouseState(&d_x, &d_y);
|
||||
|
||||
float output_speed =
|
||||
SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed,
|
||||
mouse_deadzone_offset * 128, 128.0);
|
||||
|
||||
float angle = atan2(d_y, d_x);
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, a_y));
|
||||
} else {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, 0));
|
||||
}
|
||||
}
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
||||
auto* data = (GameController*)param;
|
||||
UpdateMouse(data);
|
||||
return interval;
|
||||
}
|
||||
|
||||
} // namespace Input
|
||||
} // namespace Input
|
||||
|
@ -3,18 +3,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "array"
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "fmt/format.h"
|
||||
#include "input/controller.h"
|
||||
#include "map"
|
||||
#include "string"
|
||||
#include "unordered_set"
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
|
||||
// +1 and +2 is taken
|
||||
#define SDL_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3
|
||||
@ -40,6 +41,42 @@ struct AxisMapping {
|
||||
int value; // Value to set for key press (+127 or -127 for movement)
|
||||
};
|
||||
|
||||
enum class InputType { KeyboardMouse, Controller, Axis, Count };
|
||||
|
||||
class InputID {
|
||||
public:
|
||||
InputType type;
|
||||
u32 sdl_id;
|
||||
InputID(InputType d = InputType::Count, u32 i = (u32)-1) : type(d), sdl_id(i) {}
|
||||
bool operator==(const InputID& o) const {
|
||||
return type == o.type && sdl_id == o.sdl_id;
|
||||
}
|
||||
bool operator!=(const InputID& o) const {
|
||||
return type != o.type || sdl_id != o.sdl_id;
|
||||
}
|
||||
bool operator<=(const InputID& o) const {
|
||||
return type <= o.type && sdl_id <= o.sdl_id;
|
||||
}
|
||||
bool IsValid() const {
|
||||
return *this != InputID();
|
||||
}
|
||||
std::string ToString() {
|
||||
return fmt::format("({}: {:x})", (u8)type, sdl_id);
|
||||
}
|
||||
};
|
||||
|
||||
class InputEvent {
|
||||
public:
|
||||
InputID input;
|
||||
bool active;
|
||||
s8 axis_value;
|
||||
|
||||
InputEvent(InputID i = InputID(), bool a = false, s8 v = 0)
|
||||
: input(i), active(a), axis_value(v) {}
|
||||
InputEvent(InputType d, u32 i, bool a = false, s8 v = 0)
|
||||
: input(d, i), active(a), axis_value(v) {}
|
||||
};
|
||||
|
||||
// i strongly suggest you collapse these maps
|
||||
const std::map<std::string, OrbisPadButtonDataOffset> string_to_cbutton_map = {
|
||||
{"triangle", OrbisPadButtonDataOffset::Triangle},
|
||||
@ -187,86 +224,88 @@ const std::map<std::string, u32> string_to_keyboard_key_map = {
|
||||
{"capslock", SDLK_CAPSLOCK},
|
||||
};
|
||||
|
||||
// literally the only flag that needs external access
|
||||
void ToggleMouseEnabled();
|
||||
|
||||
void ParseInputConfig(const std::string game_id);
|
||||
|
||||
class InputBinding {
|
||||
public:
|
||||
u32 key1, key2, key3;
|
||||
InputBinding(u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) {
|
||||
InputID keys[3];
|
||||
InputBinding(InputID k1 = InputID(), InputID k2 = InputID(), InputID k3 = InputID()) {
|
||||
// we format the keys so comparing them will be very fast, because we will only have to
|
||||
// compare 3 sorted elements, where the only possible duplicate item is 0
|
||||
|
||||
// duplicate entries get changed to one original, one null
|
||||
if (k1 == k2 && k1 != SDLK_UNKNOWN) {
|
||||
k2 = 0;
|
||||
if (k1 == k2 && k1 != InputID()) {
|
||||
k2 = InputID();
|
||||
}
|
||||
if (k1 == k3 && k1 != SDLK_UNKNOWN) {
|
||||
k3 = 0;
|
||||
if (k1 == k3 && k1 != InputID()) {
|
||||
k3 = InputID();
|
||||
}
|
||||
if (k3 == k2 && k2 != SDLK_UNKNOWN) {
|
||||
k2 = 0;
|
||||
if (k3 == k2 && k2 != InputID()) {
|
||||
k2 = InputID();
|
||||
}
|
||||
// this sorts them
|
||||
if (k1 <= k2 && k1 <= k3) {
|
||||
key1 = k1;
|
||||
keys[0] = k1;
|
||||
if (k2 <= k3) {
|
||||
key2 = k2;
|
||||
key3 = k3;
|
||||
keys[1] = k2;
|
||||
keys[2] = k3;
|
||||
} else {
|
||||
key2 = k3;
|
||||
key3 = k2;
|
||||
keys[1] = k3;
|
||||
keys[2] = k2;
|
||||
}
|
||||
} else if (k2 <= k1 && k2 <= k3) {
|
||||
key1 = k2;
|
||||
keys[0] = k2;
|
||||
if (k1 <= k3) {
|
||||
key2 = k1;
|
||||
key3 = k3;
|
||||
keys[1] = k1;
|
||||
keys[2] = k3;
|
||||
} else {
|
||||
key2 = k3;
|
||||
key3 = k1;
|
||||
keys[1] = k3;
|
||||
keys[2] = k1;
|
||||
}
|
||||
} else {
|
||||
key1 = k3;
|
||||
keys[0] = k3;
|
||||
if (k1 <= k2) {
|
||||
key2 = k1;
|
||||
key3 = k2;
|
||||
keys[1] = k1;
|
||||
keys[2] = k2;
|
||||
} else {
|
||||
key2 = k2;
|
||||
key3 = k1;
|
||||
keys[1] = k2;
|
||||
keys[3] = k1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy ctor
|
||||
InputBinding(const InputBinding& o) : key1(o.key1), key2(o.key2), key3(o.key3) {}
|
||||
InputBinding(const InputBinding& o) {
|
||||
keys[0] = o.keys[0];
|
||||
keys[1] = o.keys[1];
|
||||
keys[2] = o.keys[2];
|
||||
}
|
||||
|
||||
inline bool operator==(const InputBinding& o) {
|
||||
// 0 = SDLK_UNKNOWN aka unused slot
|
||||
return (key3 == o.key3 || key3 == 0 || o.key3 == 0) &&
|
||||
(key2 == o.key2 || key2 == 0 || o.key2 == 0) &&
|
||||
(key1 == o.key1 || key1 == 0 || o.key1 == 0);
|
||||
// InputID() signifies an unused slot
|
||||
return (keys[2] == o.keys[2] || keys[2] == InputID() || o.keys[2] == InputID()) &&
|
||||
(keys[1] == o.keys[1] || keys[1] == InputID() || o.keys[1] == InputID()) &&
|
||||
(keys[0] == o.keys[0] || keys[0] == InputID() || o.keys[0] == InputID());
|
||||
// it is already very fast,
|
||||
// but reverse order makes it check the actual keys first instead of possible 0-s,
|
||||
// potenially skipping the later expressions of the three-way AND
|
||||
}
|
||||
inline int KeyCount() const {
|
||||
return (key1 ? 1 : 0) + (key2 ? 1 : 0) + (key3 ? 1 : 0);
|
||||
return (keys[0].IsValid() ? 1 : 0) + (keys[1].IsValid() ? 1 : 0) +
|
||||
(keys[2].IsValid() ? 1 : 0);
|
||||
}
|
||||
// Sorts by the amount of non zero keys - left side is 'bigger' here
|
||||
bool operator<(const InputBinding& other) const {
|
||||
return KeyCount() > other.KeyCount();
|
||||
}
|
||||
inline bool IsEmpty() {
|
||||
return key1 == 0 && key2 == 0 && key3 == 0;
|
||||
return !(keys[0].IsValid() || keys[1].IsValid() || keys[2].IsValid());
|
||||
}
|
||||
std::string ToString() {
|
||||
return fmt::format("({:X}, {:X}, {:X})", key1, key2, key3);
|
||||
std::string ToString() { // todo add device type
|
||||
return fmt::format("({:X}, {:X}, {:X})", keys[0].sdl_id, keys[1].sdl_id, keys[2].sdl_id);
|
||||
}
|
||||
|
||||
// returns a u32 based on the event type (keyboard, mouse buttons, or wheel)
|
||||
static u32 GetInputIDFromEvent(const SDL_Event& e);
|
||||
// returns an InputEvent based on the event type (keyboard, mouse buttons/wheel, or controller)
|
||||
static InputEvent GetInputEventFromSDLEvent(const SDL_Event& e);
|
||||
};
|
||||
class ControllerOutput {
|
||||
static GameController* controller;
|
||||
@ -302,19 +341,21 @@ public:
|
||||
}
|
||||
|
||||
void ResetUpdate();
|
||||
void AddUpdate(bool pressed, bool analog, u32 param = 0);
|
||||
void AddUpdate(InputEvent event);
|
||||
void FinalizeUpdate();
|
||||
};
|
||||
class BindingConnection {
|
||||
public:
|
||||
InputBinding binding;
|
||||
ControllerOutput* output;
|
||||
u32 parameter;
|
||||
BindingConnection(InputBinding b, ControllerOutput* out, u32 param = 0) {
|
||||
binding = b;
|
||||
parameter = param;
|
||||
u32 axis_param;
|
||||
InputID toggle;
|
||||
|
||||
BindingConnection(InputBinding b, ControllerOutput* out, u32 param = 0, InputID t = InputID()) {
|
||||
binding = b;
|
||||
axis_param = param;
|
||||
output = out;
|
||||
toggle = t;
|
||||
}
|
||||
bool operator<(const BindingConnection& other) const {
|
||||
// a button is a higher priority than an axis, as buttons can influence axes
|
||||
@ -329,17 +370,13 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
InputEvent ProcessBinding();
|
||||
};
|
||||
|
||||
// Updates the list of pressed keys with the given input.
|
||||
// Returns whether the list was updated or not.
|
||||
bool UpdatePressedKeys(u32 button, bool is_pressed);
|
||||
bool UpdatePressedKeys(InputEvent event);
|
||||
|
||||
void ActivateOutputsFromInputs();
|
||||
|
||||
void UpdateMouse(GameController* controller);
|
||||
|
||||
// Polls the mouse for changes, and simulates joystick movement from it.
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval);
|
||||
|
||||
} // namespace Input
|
||||
} // namespace Input
|
||||
|
74
src/input/input_mouse.cpp
Normal file
74
src/input/input_mouse.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "input/controller.h"
|
||||
#include "input_mouse.h"
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
|
||||
namespace Input {
|
||||
|
||||
int mouse_joystick_binding = 0;
|
||||
float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250;
|
||||
Uint32 mouse_polling_id = 0;
|
||||
bool mouse_enabled = false;
|
||||
|
||||
// We had to go through 3 files of indirection just to update a flag
|
||||
void ToggleMouseEnabled() {
|
||||
mouse_enabled = !mouse_enabled;
|
||||
}
|
||||
|
||||
void SetMouseToJoystick(int joystick) {
|
||||
mouse_joystick_binding = joystick;
|
||||
}
|
||||
|
||||
void SetMouseParams(float mdo, float ms, float mso) {
|
||||
mouse_deadzone_offset = mdo;
|
||||
mouse_speed = ms;
|
||||
mouse_speed_offset = mso;
|
||||
}
|
||||
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
||||
auto* controller = (GameController*)param;
|
||||
if (!mouse_enabled)
|
||||
return interval;
|
||||
|
||||
Axis axis_x, axis_y;
|
||||
switch (mouse_joystick_binding) {
|
||||
case 1:
|
||||
axis_x = Axis::LeftX;
|
||||
axis_y = Axis::LeftY;
|
||||
break;
|
||||
case 2:
|
||||
axis_x = Axis::RightX;
|
||||
axis_y = Axis::RightY;
|
||||
break;
|
||||
default:
|
||||
return interval; // no update needed
|
||||
}
|
||||
|
||||
float d_x = 0, d_y = 0;
|
||||
SDL_GetRelativeMouseState(&d_x, &d_y);
|
||||
|
||||
float output_speed =
|
||||
SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed,
|
||||
mouse_deadzone_offset * 128, 128.0);
|
||||
|
||||
float angle = atan2(d_y, d_x);
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, a_y));
|
||||
} else {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, 0));
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
} // namespace Input
|
18
src/input/input_mouse.h
Normal file
18
src/input/input_mouse.h
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Input {
|
||||
|
||||
void ToggleMouseEnabled();
|
||||
void SetMouseToJoystick(int joystick);
|
||||
void SetMouseParams(float mouse_deadzone_offset, float mouse_speed, float mouse_speed_offset);
|
||||
|
||||
// Polls the mouse for changes, and simulates joystick movement from it.
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval);
|
||||
|
||||
} // namespace Input
|
@ -15,6 +15,7 @@
|
||||
#include "imgui/renderer/imgui_core.h"
|
||||
#include "input/controller.h"
|
||||
#include "input/input_handler.h"
|
||||
#include "input/input_mouse.h"
|
||||
#include "sdl_window.h"
|
||||
#include "video_core/renderdoc.h"
|
||||
|
||||
@ -218,13 +219,14 @@ void WindowSDL::OnKeyboardMouseInput(const SDL_Event* event) {
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
// get the event's id, if it's keyup or keydown
|
||||
bool input_down = event->type == SDL_EVENT_KEY_DOWN ||
|
||||
event->type == SDL_EVENT_MOUSE_BUTTON_DOWN ||
|
||||
event->type == SDL_EVENT_MOUSE_WHEEL;
|
||||
u32 input_id = Input::InputBinding::GetInputIDFromEvent(*event);
|
||||
const bool input_down = event->type == SDL_EVENT_KEY_DOWN ||
|
||||
event->type == SDL_EVENT_MOUSE_BUTTON_DOWN ||
|
||||
event->type == SDL_EVENT_MOUSE_WHEEL;
|
||||
Input::InputEvent input_event = Input::InputBinding::GetInputEventFromSDLEvent(*event);
|
||||
|
||||
// Handle window controls outside of the input maps
|
||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||
u32 input_id = input_event.input.sdl_id;
|
||||
// Reparse kbm inputs
|
||||
if (input_id == SDLK_F8) {
|
||||
Input::ParseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial()));
|
||||
@ -258,7 +260,7 @@ void WindowSDL::OnKeyboardMouseInput(const SDL_Event* event) {
|
||||
}
|
||||
|
||||
// add/remove it from the list
|
||||
bool inputs_changed = Input::UpdatePressedKeys(input_id, input_down);
|
||||
bool inputs_changed = Input::UpdatePressedKeys(input_event);
|
||||
|
||||
// update bindings
|
||||
if (inputs_changed) {
|
||||
@ -270,7 +272,7 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) {
|
||||
|
||||
bool input_down = event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION ||
|
||||
event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN;
|
||||
u32 input_id = Input::InputBinding::GetInputIDFromEvent(*event);
|
||||
Input::InputEvent input_event = Input::InputBinding::GetInputEventFromSDLEvent(*event);
|
||||
|
||||
// the touchpad button shouldn't be rebound to anything else,
|
||||
// as it would break the entire touchpad handling
|
||||
@ -280,8 +282,10 @@ void WindowSDL::OnGamepadEvent(const SDL_Event* event) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool inputs_changed = Input::UpdatePressedKeys(input_id, input_down);
|
||||
// add/remove it from the list
|
||||
bool inputs_changed = Input::UpdatePressedKeys(input_event);
|
||||
|
||||
// update bindings
|
||||
if (inputs_changed) {
|
||||
Input::ActivateOutputsFromInputs();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user