Skip to content

Commit

Permalink
Qt/Input: Introduce profiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Megamouse committed Dec 30, 2017
1 parent 8a3759f commit 53e0652
Show file tree
Hide file tree
Showing 19 changed files with 926 additions and 643 deletions.
7 changes: 5 additions & 2 deletions rpcs3/Emu/Io/Null/NullPadHandler.h
Expand Up @@ -10,20 +10,23 @@ class NullPadHandler final : public PadHandlerBase
return true;
}

void init_config(pad_config* /*cfg*/, const std::string& /*name*/) override
{
}

std::vector<std::string> ListDevices() override
{
std::vector<std::string> nulllist;
nulllist.push_back("Default Null Device");
return nulllist;
}

bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override
bool bindPadToDevice(std::shared_ptr<Pad> /*pad*/, const std::string& /*device*/) override
{
return true;
}

void ThreadProc() override
{
}

};
91 changes: 71 additions & 20 deletions rpcs3/Emu/Io/PadHandler.h
Expand Up @@ -6,6 +6,7 @@
#include "stdafx.h"
#include "../../Utilities/Config.h"
#include "../../Utilities/types.h"
#include "Emu/System.h"

// TODO: HLE info (constants, structs, etc.) should not be available here

Expand Down Expand Up @@ -248,9 +249,53 @@ struct Pad
}
};

struct pad_config : cfg::node
struct player_config final : cfg::node
{
pad_handler def_handler = pad_handler::null;
player_config(node* owner, const std::string& name, pad_handler type) : cfg::node(owner, name), def_handler(type) {};

cfg::_enum<pad_handler> handler{ this, "Handler", def_handler };
cfg::string device{ this, "Device", handler.to_string() };
cfg::string profile{ this, "Profile", "Default Profile" };
};

struct input_config final : cfg::node
{
const std::string cfg_name = fs::get_config_dir() + "/config_input.yml";

player_config player1{ this, "Player 1 Input", pad_handler::keyboard };
player_config player2{ this, "Player 2 Input", pad_handler::null };
player_config player3{ this, "Player 3 Input", pad_handler::null };
player_config player4{ this, "Player 4 Input", pad_handler::null };
player_config player5{ this, "Player 5 Input", pad_handler::null };
player_config player6{ this, "Player 6 Input", pad_handler::null };
player_config player7{ this, "Player 7 Input", pad_handler::null };

player_config *player[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc!

bool load()
{
if (fs::file cfg_file{ cfg_name, fs::read })
{
return from_string(cfg_file.to_string());
}

return false;
}

void save()
{
fs::file(cfg_name, fs::rewrite).write(to_string());
}

bool exist()
{
return fs::is_file(cfg_name);
}
};

struct pad_config final : cfg::node
{
std::string cfg_type = "";
std::string cfg_name = "";

cfg::string ls_left { this, "Left Stick Left", "" };
Expand Down Expand Up @@ -314,6 +359,8 @@ struct pad_config : cfg::node
}
};

static input_config input_cfg;

class PadHandlerBase
{
protected:
Expand All @@ -327,7 +374,7 @@ class PadHandlerBase
bool b_has_deadzones = false;
bool b_has_rumble = false;
bool b_has_config = false;
pad_config m_pad_config;
std::array<pad_config, MAX_GAMEPADS> m_pad_configs;

template <typename T>
T lerp(T v0, T v1, T t) {
Expand Down Expand Up @@ -364,15 +411,15 @@ class PadHandlerBase
{
std::string def = name.def;
std::string nam = name.to_string();
int def_code = -1;
long def_code = -1;

for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == nam)
return it->first;
return static_cast<long>(it->first);

if (fallback && it->second == def)
def_code = it->first;
def_code = static_cast<long>(it->first);
}

if (fallback)
Expand Down Expand Up @@ -409,7 +456,7 @@ class PadHandlerBase
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return it->first;
return static_cast<long>(it->first);
}

if (fallback)
Expand Down Expand Up @@ -442,41 +489,41 @@ class PadHandlerBase
float ScaleStickInput(s32 raw_value, int minimum, int maximum)
{
// value based on max range converted to [0, 1]
float val = float(Clamp(raw_value, minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
float val = float(Clamp(static_cast<f32>(raw_value), minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
return 255.0f * val;
};

// Get new scaled value between -255 and 255 based on its minimum and maximum
float ScaleStickInput2(s32 raw_value, int minimum, int maximum)
{
// value based on max range converted to [0, 1]
float val = float(Clamp(raw_value, minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
float val = float(Clamp(static_cast<f32>(raw_value), minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
return (510.0f * val) - 255.0f;
};

// normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions
// the input values must lie in 0+
u16 NormalizeDirectedInput(u16 raw_value, float threshold, float maximum)
u16 NormalizeDirectedInput(u16 raw_value, s32 threshold, s32 maximum)
{
if (threshold >= maximum || maximum <= 0)
{
return static_cast<u16>(0);
}

float val = float(Clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1]
float val = float(Clamp(raw_value, 0, maximum)) / float(maximum); // value based on max range converted to [0, 1]

if (threshold <= 0)
{
return static_cast<u16>(255.0f * val);
}
else
{
float thresh = threshold / maximum; // threshold converted to [0, 1]
float thresh = float(threshold) / float(maximum); // threshold converted to [0, 1]
return static_cast<u16>(255.0f * std::min(1.0f, (val - thresh) / (1.0f - thresh)));
}
};

u16 NormalizeStickInput(s32 raw_value, int threshold, bool ignore_threshold = false)
u16 NormalizeStickInput(u16 raw_value, int threshold, bool ignore_threshold = false)
{
if (ignore_threshold)
{
Expand Down Expand Up @@ -555,7 +602,7 @@ class PadHandlerBase
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// This function assumes inX and inY is already in 0-255
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY, float squircle_factor)
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY, int squircle_factor)
{
// convert inX and Y to a (-1, 1) vector;
const f32 x = ((f32)inX - 127.5f) / 127.5f;
Expand All @@ -567,7 +614,7 @@ class PadHandlerBase

// now find len/point on the given squircle from our current angle and radius in polar coords
// https://thatsmaths.com/2016/07/14/squircles/
const f32 newLen = (1 + std::pow(std::sin(2 * angle), 2.f) / (squircle_factor / 1000.f)) * r;
const f32 newLen = (1 + std::pow(std::sin(2 * angle), 2.f) / (float(squircle_factor) / 1000.f)) * r;

// we now have len and angle, convert to cartisian
const int newX = Clamp0To255(((newLen * std::cos(angle)) + 1) * 127.5f);
Expand All @@ -584,24 +631,28 @@ class PadHandlerBase
s32 vibration_max = 255;
u32 connected = 0;

pad_handler m_type = pad_handler::null;

virtual bool Init() { return true; };
virtual ~PadHandlerBase() = default;

//Does it have GUI Config?
bool has_config() { return b_has_config; };
bool has_rumble() { return b_has_rumble; };
bool has_deadzones() { return b_has_deadzones; };
pad_config* GetConfig() { return &m_pad_config; };
static std::string get_config_dir(pad_handler type) { return fs::get_config_dir() + "/InputConfigs/" + fmt::format("%s", type) + "/"; };
static std::string get_config_filename(const input_config& cfg, int i) { return fs::get_config_dir() + "/InputConfigs/" + cfg.player[i]->handler.to_string() + "/" + cfg.player[i]->profile.to_string() + ".yml"; };
//Sets window to config the controller(optional)
virtual void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) {};
virtual void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) {};
virtual void GetNextButtonPress(const std::string& /*padId*/, const std::function<void(u16, std::string, int[])>& /*callback*/, bool /*get_blacklist*/ = false, std::vector<std::string> /*buttons*/ = {}) {};
virtual void TestVibration(const std::string& /*padId*/, u32 /*largeMotor*/, u32 /*smallMotor*/) {};
//Return list of devices for that handler
virtual std::vector<std::string> ListDevices() = 0;
//Callback called during pad_thread::ThreadFunc
virtual void ThreadProc() = 0;
//Binds a Pad to a device
virtual bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) = 0;
virtual bool bindPadToDevice(std::shared_ptr<Pad> /*pad*/, const std::string& /*device*/) = 0;
virtual void init_config(pad_config* /*cfg*/, const std::string& /*name*/) = 0;

private:
virtual void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) {};
virtual void TranslateButtonPress(u64 /*keyCode*/, bool& /*pressed*/, u16& /*val*/, bool /*ignore_threshold*/ = false) {};
};

0 comments on commit 53e0652

Please sign in to comment.