mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
Output update handling, and reworked file creating, reading and parsing
This commit is contained in:
parent
1884b39eb8
commit
d92a83ccb5
@ -701,4 +701,115 @@ void setDefaultValues() {
|
||||
gpuId = -1;
|
||||
}
|
||||
|
||||
std::string_view getDefaultKeyboardConfig() {
|
||||
static std::string_view default_config =
|
||||
R"(#This is the default keybinding config
|
||||
#To change per-game configs, modify the CUSAXXXXX.ini files
|
||||
#To change the default config that applies to new games without already existing configs, modify default.ini
|
||||
#If you don't like certain mappings, delete, change or comment them out.
|
||||
#You can add any amount of KBM keybinds to a single controller input,
|
||||
#but you can use each KBM keybind for one controller input.
|
||||
|
||||
#Keybinds used by the emulator (these are unchangeable):
|
||||
#F11 : fullscreen
|
||||
#F10 : FPS counter
|
||||
#F9 : toggle mouse-to-joystick input
|
||||
# (it overwrites everything else to that joystick, so this is required)
|
||||
#F8 : reparse keyboard input(this)
|
||||
|
||||
#This is a mapping for Bloodborne, inspired by other Souls titles on PC.
|
||||
|
||||
#Specifies which joystick the mouse movement controls.
|
||||
mouse_to_joystick = right;
|
||||
|
||||
#Use healing item, change status in inventory
|
||||
triangle = f;
|
||||
#Dodge, back in inventory
|
||||
circle = space;
|
||||
#Interact, select item in inventory
|
||||
cross = e;
|
||||
#Use quick item, remove item in inventory
|
||||
square = r;
|
||||
|
||||
#Emergency extra bullets
|
||||
up = w, lalt;
|
||||
up = mousewheelup;
|
||||
#Change quick item
|
||||
down = s, lalt;
|
||||
down = mousewheeldown;
|
||||
#Change weapon in left hand
|
||||
left = a, lalt;
|
||||
left = mousewheelleft;
|
||||
#Change weapon in right hand
|
||||
right = d, lalt;
|
||||
right = mousewheelright;
|
||||
#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus
|
||||
modkey_toggle = i, lalt;
|
||||
|
||||
#Menu
|
||||
options = escape;
|
||||
#Gestures
|
||||
touchpad = g;
|
||||
|
||||
#Transform
|
||||
l1 = rightbutton, lshift;
|
||||
#Shoot
|
||||
r1 = leftbutton;
|
||||
#Light attack
|
||||
l2 = rightbutton;
|
||||
#Heavy attack
|
||||
r2 = leftbutton, lshift;
|
||||
#Does nothing
|
||||
l3 = x;
|
||||
#Center cam, lock on
|
||||
r3 = q;
|
||||
r3 = middlebutton;
|
||||
|
||||
#Axis mappings
|
||||
#Move
|
||||
axis_left_x_minus = a;
|
||||
axis_left_x_plus = d;
|
||||
axis_left_y_minus = w;
|
||||
axis_left_y_plus = s;
|
||||
#Change to 'walk mode' by holding the following key:
|
||||
leftjoystick_halfmode = lctrl;
|
||||
)";
|
||||
return default_config;
|
||||
}
|
||||
std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id) {
|
||||
// Read configuration file of the game, and if it doesn't exist, generate it from default
|
||||
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
||||
// If even the folder is missing, we start with that.
|
||||
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig";
|
||||
const auto config_file = config_dir / (game_id + ".ini");
|
||||
const auto default_config_file = config_dir / "default.ini";
|
||||
|
||||
// Ensure the config directory exists
|
||||
if (!std::filesystem::exists(config_dir)) {
|
||||
std::filesystem::create_directories(config_dir);
|
||||
}
|
||||
|
||||
// Check if the default config exists
|
||||
if (!std::filesystem::exists(default_config_file)) {
|
||||
// If the default config is also missing, create it from getDefaultConfig()
|
||||
const auto default_config = getDefaultKeyboardConfig();
|
||||
std::ofstream default_config_stream(default_config_file);
|
||||
if (default_config_stream) {
|
||||
default_config_stream << default_config;
|
||||
}
|
||||
}
|
||||
|
||||
// if empty, we only need to execute the function up until this point
|
||||
if(game_id.empty()) {
|
||||
return default_config_file;
|
||||
}
|
||||
|
||||
// If game-specific config doesn't exist, create it from the default config
|
||||
if (!std::filesystem::exists(config_file)) {
|
||||
std::filesystem::copy(default_config_file, config_file);
|
||||
}
|
||||
return config_file;
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
|
@ -123,6 +123,9 @@ std::string getEmulatorLanguage();
|
||||
|
||||
void setDefaultValues();
|
||||
|
||||
// todo: name and function location pending
|
||||
std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id = "");
|
||||
|
||||
// settings
|
||||
u32 GetLanguage();
|
||||
}; // namespace Config
|
||||
|
@ -44,122 +44,16 @@ 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;
|
||||
|
||||
std::string_view getDefaultKeyboardConfig() {
|
||||
static std::string_view default_config =
|
||||
R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
## SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#This is the default keybinding config
|
||||
#To change per-game configs, modify the CUSAXXXXX.ini files
|
||||
#To change the default config that applies to new games without already existing configs, modify default.ini
|
||||
#If you don't like certain mappings, delete, change or comment them out.
|
||||
#You can add any amount of KBM keybinds to a single controller input,
|
||||
#but you can use each KBM keybind for one controller input.
|
||||
|
||||
#Keybinds used by the emulator (these are unchangeable):
|
||||
#F11 : fullscreen
|
||||
#F10 : FPS counter
|
||||
#F9 : toggle mouse-to-joystick input
|
||||
# (it overwrites everything else to that joystick, so this is required)
|
||||
#F8 : reparse keyboard input(this)
|
||||
|
||||
#This is a mapping for Bloodborne, inspired by other Souls titles on PC.
|
||||
|
||||
#Specifies which joystick the mouse movement controls.
|
||||
mouse_to_joystick = right;
|
||||
|
||||
#Use healing item, change status in inventory
|
||||
triangle = f;
|
||||
#Dodge, back in inventory
|
||||
circle = space;
|
||||
#Interact, select item in inventory
|
||||
cross = e;
|
||||
#Use quick item, remove item in inventory
|
||||
square = r;
|
||||
|
||||
#Emergency extra bullets
|
||||
up = w, lalt;
|
||||
up = mousewheelup;
|
||||
#Change quick item
|
||||
down = s, lalt;
|
||||
down = mousewheeldown;
|
||||
#Change weapon in left hand
|
||||
left = a, lalt;
|
||||
left = mousewheelleft;
|
||||
#Change weapon in right hand
|
||||
right = d, lalt;
|
||||
right = mousewheelright;
|
||||
#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus
|
||||
modkey_toggle = i, lalt;
|
||||
|
||||
#Menu
|
||||
options = escape;
|
||||
#Gestures
|
||||
touchpad = g;
|
||||
|
||||
#Transform
|
||||
l1 = rightbutton, lshift;
|
||||
#Shoot
|
||||
r1 = leftbutton;
|
||||
#Light attack
|
||||
l2 = rightbutton;
|
||||
#Heavy attack
|
||||
r2 = leftbutton, lshift;
|
||||
#Does nothing
|
||||
l3 = x;
|
||||
#Center cam, lock on
|
||||
r3 = q;
|
||||
r3 = middlebutton;
|
||||
|
||||
#Axis mappings
|
||||
#Move
|
||||
axis_left_x_minus = a;
|
||||
axis_left_x_plus = d;
|
||||
axis_left_y_minus = w;
|
||||
axis_left_y_plus = s;
|
||||
#Change to 'walk mode' by holding the following key:
|
||||
leftjoystick_halfmode = lctrl;
|
||||
)";
|
||||
return default_config;
|
||||
}
|
||||
|
||||
void parseInputConfig(const std::string game_id = "") {
|
||||
// Read configuration file of the game, and if it doesn't exist, generate it from default
|
||||
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
||||
// If even the folder is missing, we start with that.
|
||||
|
||||
const auto config_file = Config::getFoolproofKbmConfigFile(game_id);
|
||||
|
||||
// maybe extract this?
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig";
|
||||
const auto config_file = config_dir / (game_id + ".ini");
|
||||
const auto default_config_file = config_dir / "default.ini";
|
||||
|
||||
// Ensure the config directory exists
|
||||
if (!std::filesystem::exists(config_dir)) {
|
||||
std::filesystem::create_directories(config_dir);
|
||||
}
|
||||
|
||||
// Try loading the game-specific config file
|
||||
if (!std::filesystem::exists(config_file)) {
|
||||
// If game-specific config doesn't exist, check for the default config
|
||||
if (!std::filesystem::exists(default_config_file)) {
|
||||
// If the default config is also missing, create it from getDefaultConfig()
|
||||
const auto default_config = getDefaultKeyboardConfig();
|
||||
std::ofstream default_config_stream(default_config_file);
|
||||
if (default_config_stream) {
|
||||
default_config_stream << default_config;
|
||||
}
|
||||
}
|
||||
|
||||
// If default config now exists, copy it to the game-specific config file
|
||||
if (std::filesystem::exists(default_config_file) && !game_id.empty()) {
|
||||
std::filesystem::copy(default_config_file, config_file);
|
||||
}
|
||||
}
|
||||
// if we just called the function to generate the directory and the default .ini
|
||||
if (game_id.empty()) {
|
||||
// todo: change usages of this to getFoolproofKbmConfigFile (gui)
|
||||
if(game_id == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// todo
|
||||
// we reset these here so in case the user fucks up or doesn't include this we can fall back to
|
||||
// default
|
||||
mouse_deadzone_offset = 0.5;
|
||||
@ -293,17 +187,18 @@ void ControllerOutput::setControllerOutputController(GameController* c) {
|
||||
ControllerOutput::controller = c;
|
||||
}
|
||||
|
||||
void ControllerOutput::update(bool pressed, int axis_direction) {
|
||||
void ControllerOutput::update(bool pressed, int axis_value) {
|
||||
float touchpad_x = 0;
|
||||
Input::Axis axis = Input::Axis::AxisMax;
|
||||
if(button != 0){
|
||||
switch (button) {
|
||||
/* todo
|
||||
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2:
|
||||
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2:
|
||||
axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Input::Axis::TriggerRight
|
||||
: Input::Axis::TriggerLeft;
|
||||
controller->Axis(0, axis, Input::GetAxis(0, 0x80, pressed ? 255 : 0));
|
||||
axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Axis::TriggerRight
|
||||
: Axis::TriggerLeft;
|
||||
controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0));
|
||||
break;
|
||||
*/
|
||||
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD:
|
||||
touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f
|
||||
: Config::getBackButtonBehavior() == "right" ? 0.75f
|
||||
@ -311,26 +206,37 @@ void ControllerOutput::update(bool pressed, int axis_direction) {
|
||||
controller->SetTouchpadState(0, true, touchpad_x, 0.5f);
|
||||
controller->CheckButton(0, button, pressed);
|
||||
break;
|
||||
default: // is a normal key
|
||||
case LEFTJOYSTICK_HALFMODE:
|
||||
leftjoystick_halfmode ^= pressed; // toggle if pressed, don't change otherwise
|
||||
break;
|
||||
case RIGHTJOYSTICK_HALFMODE:
|
||||
rightjoystick_halfmode ^= pressed;
|
||||
break;
|
||||
default: // is a normal key (hopefully)
|
||||
controller->CheckButton(0, button, pressed);
|
||||
break;
|
||||
}
|
||||
} else if (axis != Axis::AxisMax) {
|
||||
float multiplier = 1.0;
|
||||
switch (axis) {
|
||||
case Input::Axis::LeftX:
|
||||
case Input::Axis::LeftY:
|
||||
case Axis::LeftX:
|
||||
case Axis::LeftY:
|
||||
multiplier = leftjoystick_halfmode ? 0.5 : 1.0;
|
||||
break;
|
||||
case Input::Axis::RightX:
|
||||
case Input::Axis::RightY:
|
||||
case Axis::RightX:
|
||||
case Axis::RightY:
|
||||
multiplier = rightjoystick_halfmode ? 0.5 : 1.0;
|
||||
break;
|
||||
case Axis::TriggerLeft:
|
||||
case Axis::TriggerRight:
|
||||
// todo: verify this works
|
||||
controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int output_value = (pressed ? axis_value : 0) * multiplier;
|
||||
int ax = Input::GetAxis(-0x80, 0x80, output_value);
|
||||
int ax = GetAxis(-0x80, 0x80, output_value);
|
||||
controller->Axis(0, axis, ax);
|
||||
} else {
|
||||
LOG_ERROR(Input, "Controller output with no values detected!");
|
||||
@ -366,11 +272,11 @@ void updateMouse(GameController* controller) {
|
||||
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, Input::GetAxis(-0x80, 0x80, a_x));
|
||||
controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, a_y));
|
||||
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, Input::GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "map"
|
||||
#include "string"
|
||||
#include "common/types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "input/controller.h"
|
||||
|
||||
@ -174,9 +175,8 @@ void parseInputConfig(const std::string game_id);
|
||||
class InputBinding {
|
||||
public:
|
||||
u32 key1, key2, key3;
|
||||
int axis_value;
|
||||
InputBinding(int v, u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) {
|
||||
// we format the keys so comaring them will be very fast, because we will only have to compare 3 sorted elements,
|
||||
InputBinding(u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) {
|
||||
// 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
|
||||
@ -198,6 +198,8 @@ public:
|
||||
else { key2 = k2; key3 = k1; }
|
||||
}
|
||||
}
|
||||
// copy ctor
|
||||
InputBinding(const InputBinding& o) : key1(o.key1), key2(o.key2), key3(o.key3) {}
|
||||
|
||||
inline bool operator==(const InputBinding& o) {
|
||||
// 0 = SDLK_UNKNOWN aka unused slot
|
||||
@ -209,6 +211,7 @@ public:
|
||||
// potenially skipping the later expressions of the three-way AND
|
||||
}
|
||||
|
||||
// returns a u32 based on the event type (keyboard, mouse buttons, or wheel)
|
||||
static u32 getInputIDFromEvent(const SDL_Event& e) {
|
||||
switch(e.type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
@ -229,43 +232,44 @@ class ControllerOutput {
|
||||
public:
|
||||
static void setControllerOutputController(GameController* c);
|
||||
|
||||
std::string name;
|
||||
u32 button;
|
||||
Input::Axis axis;
|
||||
int axis_value;
|
||||
bool active;
|
||||
ControllerOutput(const std::string& n, u32 b, Axis a = Axis::AxisMax, int v = 0, bool ac = false) {
|
||||
name = n;
|
||||
Axis axis;
|
||||
|
||||
ControllerOutput(u32 b, Axis a = Axis::AxisMax) {
|
||||
button = b;
|
||||
axis = a;
|
||||
axis_value = v;
|
||||
active = ac;
|
||||
}
|
||||
ControllerOutput(const ControllerOutput& o);
|
||||
ControllerOutput(const ControllerOutput& o) : button(o.button), axis(o.axis) {}
|
||||
void update(bool pressed, int axis_direction = 0);
|
||||
};
|
||||
class InputData {
|
||||
class BindingConnection {
|
||||
public:
|
||||
InputBinding binding;
|
||||
ControllerOutput* output;
|
||||
int axis_value;
|
||||
bool flag;
|
||||
InputData(InputBinding b, int v = 0) : binding(b), axis_value(v), flag(false) {}
|
||||
BindingConnection(InputBinding b, ControllerOutput* out, int a_v = 0) {
|
||||
binding = b;
|
||||
axis_value = 0;
|
||||
|
||||
// todo: check if out is in the allowed array
|
||||
output = out;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// todo
|
||||
// don't forget to change the number too
|
||||
const std::array<ControllerOutput, 4> input_state = {
|
||||
// buttons and axes rolled into one
|
||||
ControllerOutput("up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP),
|
||||
ControllerOutput("down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN),
|
||||
// etc.
|
||||
ControllerOutput("axis_left_x_plus", 0, Axis::LeftX, 127),
|
||||
ControllerOutput("axis_left_x_minus", 0, Axis::LeftX, -127),
|
||||
const std::array<ControllerOutput, 4> output_array = {
|
||||
ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP),
|
||||
ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN),
|
||||
|
||||
ControllerOutput(0, Axis::TriggerLeft),
|
||||
ControllerOutput(0, Axis::LeftY),
|
||||
// etc.
|
||||
};
|
||||
|
||||
|
||||
extern std::map<InputData, ControllerOutput&> new_binding_map;
|
||||
extern std::map<BindingConnection, ControllerOutput&> new_binding_map;
|
||||
extern u32 pressed_keys[];
|
||||
|
||||
// Check if the 3 key input is currently active.
|
||||
|
Loading…
Reference in New Issue
Block a user