1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2025-01-31 20:41:45 +01:00

Qt/Input: Introduce profiles

This commit is contained in:
Unknown 2017-12-23 22:25:51 +01:00 committed by Ivan
parent 4231ea2eb6
commit 51a2b43d81
24 changed files with 1194 additions and 893 deletions

View File

@ -10,6 +10,10 @@ public:
return true; return true;
} }
void init_config(pad_config* /*cfg*/, const std::string& /*name*/) override
{
}
std::vector<std::string> ListDevices() override std::vector<std::string> ListDevices() override
{ {
std::vector<std::string> nulllist; std::vector<std::string> nulllist;
@ -17,7 +21,7 @@ public:
return nulllist; 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; return true;
} }
@ -25,5 +29,4 @@ public:
void ThreadProc() override void ThreadProc() override
{ {
} }
}; };

288
rpcs3/Emu/Io/PadHandler.cpp Normal file
View File

@ -0,0 +1,288 @@
#include "stdafx.h"
#include "PadHandler.h"
cfg_input g_cfg_input;
PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type)
{
}
// Search an unordered map for a string value and return found keycode
int PadHandlerBase::FindKeyCode(std::unordered_map<u32, std::string> map, const cfg::string& name, bool fallback)
{
std::string def = name.def;
std::string nam = name.to_string();
int def_code = -1;
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == nam)
return it->first;
if (fallback && it->second == def)
def_code = it->first;
}
if (fallback)
{
LOG_ERROR(HLE, "int FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def);
if (def_code < 0)
def_code = 0;
}
return def_code;
}
long PadHandlerBase::FindKeyCode(std::unordered_map<u64, std::string> map, const cfg::string& name, bool fallback)
{
std::string def = name.def;
std::string nam = name.to_string();
long def_code = -1;
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == nam)
return static_cast<long>(it->first);
if (fallback && it->second == def)
def_code = static_cast<long>(it->first);
}
if (fallback)
{
LOG_ERROR(HLE, "long FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def);
if (def_code < 0)
def_code = 0;
}
return def_code;
}
// Search an unordered map for a string value and return found keycode
int PadHandlerBase::FindKeyCodeByString(std::unordered_map<u32, std::string> map, const std::string& name, bool fallback)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return it->first;
}
if (fallback)
{
LOG_ERROR(HLE, "long FindKeyCodeByString fohr [name = %s] returned with 0", name);
return 0;
}
return -1;
}
// Search an unordered map for a string value and return found keycode
long PadHandlerBase::FindKeyCodeByString(std::unordered_map<u64, std::string> map, const std::string& name, bool fallback)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return static_cast<long>(it->first);
}
if (fallback)
{
LOG_ERROR(HLE, "long FindKeyCodeByString fohr [name = %s] returned with 0", name);
return 0;
}
return -1;
}
// Get new scaled value between 0 and 255 based on its minimum and maximum
float PadHandlerBase::ScaleStickInput(s32 raw_value, int minimum, int maximum)
{
// value based on max range converted to [0, 1]
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 PadHandlerBase::ScaleStickInput2(s32 raw_value, int minimum, int maximum)
{
// value based on max range converted to [0, 1]
float val = float(Clamp(static_cast<f32>(raw_value), minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
return (510.0f * val) - 255.0f;
}
// Get normalized trigger value based on the range defined by a threshold
u16 PadHandlerBase::NormalizeTriggerInput(u16 value, int threshold)
{
if (value <= threshold || threshold >= trigger_max)
{
return static_cast<u16>(0);
}
else if (threshold <= trigger_min)
{
return value;
}
else
{
return (u16)(float(trigger_max) * float(value - threshold) / float(trigger_max - threshold));
}
}
// 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 PadHandlerBase::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)) / float(maximum); // value based on max range converted to [0, 1]
if (threshold <= 0)
{
return static_cast<u16>(255.0f * val);
}
else
{
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 PadHandlerBase::NormalizeStickInput(u16 raw_value, int threshold, bool ignore_threshold)
{
if (ignore_threshold)
{
return static_cast<u16>(ScaleStickInput(raw_value, 0, thumb_max));
}
else
{
return NormalizeDirectedInput(raw_value, threshold, thumb_max);
}
}
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
// return is new x and y values in 0-255 range
std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone)
{
const float dzRange = deadzone / float((std::abs(thumb_max) + std::abs(thumb_min)));
float X = inX / 255.0f;
float Y = inY / 255.0f;
if (dzRange > 0.f)
{
const float mag = std::min(sqrtf(X*X + Y*Y), 1.f);
if (mag <= 0)
{
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
}
if (mag > dzRange) {
float pos = lerp(0.13f, 1.f, (mag - dzRange) / (1 - dzRange));
float scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
else {
float pos = lerp(0.f, 0.13f, mag / dzRange);
float scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
}
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
}
// get clamped value between min and max
s32 PadHandlerBase::Clamp(f32 input, s32 min, s32 max)
{
if (input > max)
return max;
else if (input < min)
return min;
else return static_cast<s32>(input);
}
// get clamped value between 0 and 255
u16 PadHandlerBase::Clamp0To255(f32 input)
{
return static_cast<u16>(Clamp(input, 0, 255));
}
// get clamped value between 0 and 1023
u16 PadHandlerBase::Clamp0To1023(f32 input)
{
return static_cast<u16>(Clamp(input, 0, 1023));
}
// input has to be [-1,1]. result will be [0,255]
u16 PadHandlerBase::ConvertAxis(float value)
{
return static_cast<u16>((value + 1.0)*(255.0 / 2.0));
}
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// 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> PadHandlerBase::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;
const f32 y = ((f32)inY - 127.5f) / 127.5f;
// compute angle and len of given point to be used for squircle radius
const f32 angle = std::atan2(y, x);
const f32 r = std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f));
// 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) / (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);
const int newY = Clamp0To255(((newLen * std::sin(angle)) + 1) * 127.5f);
return std::tuple<u16, u16>(newX, newY);
}
bool PadHandlerBase::has_config()
{
return b_has_config;
}
bool PadHandlerBase::has_rumble()
{
return b_has_rumble;
}
bool PadHandlerBase::has_deadzones()
{
return b_has_deadzones;
}
std::string PadHandlerBase::get_config_dir(pad_handler type)
{
return fs::get_config_dir() + "/InputConfigs/" + fmt::format("%s", type) + "/";
}
std::string PadHandlerBase::get_config_filename(int i)
{
return fs::get_config_dir() + "/InputConfigs/" + g_cfg_input.player[i]->handler.to_string() + "/" + g_cfg_input.player[i]->profile.to_string() + ".yml";
}
void PadHandlerBase::init_configs()
{
int index = 0;
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (g_cfg_input.player[i]->handler == m_type)
{
init_config(&m_pad_configs[index], get_config_filename(i));
index++;
}
}
}

View File

@ -6,6 +6,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "../../Utilities/Config.h" #include "../../Utilities/Config.h"
#include "../../Utilities/types.h" #include "../../Utilities/types.h"
#include "Emu/System.h"
// TODO: HLE info (constants, structs, etc.) should not be available here // TODO: HLE info (constants, structs, etc.) should not be available here
@ -248,9 +249,50 @@ struct Pad
} }
}; };
struct pad_config : cfg::node struct cfg_player final : cfg::node
{
pad_handler def_handler = pad_handler::null;
cfg_player(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 cfg_input final : cfg::node
{
const std::string cfg_name = fs::get_config_dir() + "/config_input.yml";
cfg_player player1{ this, "Player 1 Input", pad_handler::keyboard };
cfg_player player2{ this, "Player 2 Input", pad_handler::null };
cfg_player player3{ this, "Player 3 Input", pad_handler::null };
cfg_player player4{ this, "Player 4 Input", pad_handler::null };
cfg_player player5{ this, "Player 5 Input", pad_handler::null };
cfg_player player6{ this, "Player 6 Input", pad_handler::null };
cfg_player player7{ this, "Player 7 Input", pad_handler::null };
cfg_player *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());
};
};
extern cfg_input g_cfg_input;
struct pad_config final : cfg::node
{ {
std::string cfg_type = "";
std::string cfg_name = ""; std::string cfg_name = "";
cfg::string ls_left { this, "Left Stick Left", "" }; cfg::string ls_left { this, "Left Stick Left", "" };
@ -327,7 +369,7 @@ protected:
bool b_has_deadzones = false; bool b_has_deadzones = false;
bool b_has_rumble = false; bool b_has_rumble = false;
bool b_has_config = false; bool b_has_config = false;
pad_config m_pad_config; std::array<pad_config, MAX_GAMEPADS> m_pad_configs;
template <typename T> template <typename T>
T lerp(T v0, T v1, T t) { T lerp(T v0, T v1, T t) {
@ -335,245 +377,52 @@ protected:
} }
// Search an unordered map for a string value and return found keycode // Search an unordered map for a string value and return found keycode
int FindKeyCode(std::unordered_map<u32, std::string> map, const cfg::string& name, bool fallback = true) int FindKeyCode(std::unordered_map<u32, std::string> map, const cfg::string& name, bool fallback = true);
{
std::string def = name.def;
std::string nam = name.to_string();
int def_code = -1;
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == nam)
return it->first;
if (fallback && it->second == def)
def_code = it->first;
}
if (fallback)
{
LOG_ERROR(HLE, "int FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def);
if (def_code < 0)
def_code = 0;
}
return def_code;
};
long FindKeyCode(std::unordered_map<u64, std::string> map, const cfg::string& name, bool fallback = true)
{
std::string def = name.def;
std::string nam = name.to_string();
int def_code = -1;
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == nam)
return it->first;
if (fallback && it->second == def)
def_code = it->first;
}
if (fallback)
{
LOG_ERROR(HLE, "long FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def);
if (def_code < 0)
def_code = 0;
}
return def_code;
};
// Search an unordered map for a string value and return found keycode // Search an unordered map for a string value and return found keycode
int FindKeyCodeByString(std::unordered_map<u32, std::string> map, const std::string& name, bool fallback = true) long FindKeyCode(std::unordered_map<u64, std::string> map, const cfg::string& name, bool fallback = true);
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return it->first;
}
if (fallback)
{
LOG_ERROR(HLE, "long FindKeyCodeByString fohr [name = %s] returned with 0", name);
return 0;
}
return -1;
};
// Search an unordered map for a string value and return found keycode // Search an unordered map for a string value and return found keycode
long FindKeyCodeByString(std::unordered_map<u64, std::string> map, const std::string& name, bool fallback = true) int FindKeyCodeByString(std::unordered_map<u32, std::string> map, const std::string& name, bool fallback = true);
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return it->first;
}
if (fallback) // Search an unordered map for a string value and return found keycode
{ long FindKeyCodeByString(std::unordered_map<u64, std::string> map, const std::string& name, bool fallback = true);
LOG_ERROR(HLE, "long FindKeyCodeByString fohr [name = %s] returned with 0", name);
return 0;
}
return -1;
};
// Get normalized trigger value based on the range defined by a threshold
u16 NormalizeTriggerInput(u16 value, int threshold)
{
if (value <= threshold || threshold >= trigger_max)
{
return static_cast<u16>(0);
}
else if (threshold <= trigger_min)
{
return value;
}
else
{
return (u16)(float(trigger_max) * float(value - threshold) / float(trigger_max - threshold));
}
};
// Get new scaled value between 0 and 255 based on its minimum and maximum // Get new scaled value between 0 and 255 based on its minimum and maximum
float ScaleStickInput(s32 raw_value, int minimum, int maximum) 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));
return 255.0f * val;
};
// Get new scaled value between -255 and 255 based on its minimum and maximum // Get new scaled value between -255 and 255 based on its minimum and maximum
float ScaleStickInput2(s32 raw_value, int minimum, int maximum) float ScaleStickInput2(s32 raw_value, int minimum, int maximum);
{
// value based on max range converted to [0, 1] // Get normalized trigger value based on the range defined by a threshold
float val = float(Clamp(raw_value, minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum)); u16 NormalizeTriggerInput(u16 value, int threshold);
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 // 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+ // 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] u16 NormalizeStickInput(u16 raw_value, int threshold, bool ignore_threshold = false);
if (threshold <= 0)
{
return static_cast<u16>(255.0f * val);
}
else
{
float thresh = threshold / 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)
{
if (ignore_threshold)
{
return static_cast<u16>(ScaleStickInput(raw_value, 0, thumb_max));
}
else
{
return NormalizeDirectedInput(raw_value, threshold, thumb_max);
}
}
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% // This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range // X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
// return is new x and y values in 0-255 range // return is new x and y values in 0-255 range
std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone) std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone);
{
const float dzRange = deadzone / float((std::abs(thumb_max) + std::abs(thumb_min)));
float X = inX / 255.0f;
float Y = inY / 255.0f;
if (dzRange > 0.f)
{
const float mag = std::min(sqrtf(X*X + Y*Y), 1.f);
if (mag <= 0)
{
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
}
if (mag > dzRange) {
float pos = lerp(0.13f, 1.f, (mag - dzRange) / (1 - dzRange));
float scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
else {
float pos = lerp(0.f, 0.13f, mag / dzRange);
float scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
}
return std::tuple<u16, u16>( ConvertAxis(X), ConvertAxis(Y) );
};
// get clamped value between min and max // get clamped value between min and max
s32 Clamp(f32 input, s32 min, s32 max) s32 Clamp(f32 input, s32 min, s32 max);
{
if (input > max)
return max;
else if (input < min)
return min;
else return static_cast<s32>(input);
};
// get clamped value between 0 and 255 // get clamped value between 0 and 255
u16 Clamp0To255(f32 input) u16 Clamp0To255(f32 input);
{
return static_cast<u16>(Clamp(input, 0, 255));
};
// get clamped value between 0 and 1023 // get clamped value between 0 and 1023
u16 Clamp0To1023(f32 input) u16 Clamp0To1023(f32 input);
{
return static_cast<u16>(Clamp(input, 0, 1023));
}
// input has to be [-1,1]. result will be [0,255] // input has to be [-1,1]. result will be [0,255]
u16 ConvertAxis(float value) u16 ConvertAxis(float value);
{
return static_cast<u16>((value + 1.0)*(255.0 / 2.0));
};
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle // The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange // 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 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 // 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;
const f32 y = ((f32)inY - 127.5f) / 127.5f;
// compute angle and len of given point to be used for squircle radius
const f32 angle = std::atan2(y, x);
const f32 r = std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f));
// 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;
// we now have len and angle, convert to cartisian
const int newX = Clamp0To255(((newLen * std::cos(angle)) + 1) * 127.5f);
const int newY = Clamp0To255(((newLen * std::sin(angle)) + 1) * 127.5f);
return std::tuple<u16, u16>(newX, newY);
}
public: public:
s32 thumb_min = 0; s32 thumb_min = 0;
@ -584,24 +433,32 @@ public:
s32 vibration_max = 255; s32 vibration_max = 255;
u32 connected = 0; u32 connected = 0;
virtual bool Init() { return true; }; pad_handler m_type = pad_handler::null;
virtual ~PadHandlerBase() = default;
//Does it have GUI Config? bool has_config();
bool has_config() { return b_has_config; }; bool has_rumble();
bool has_rumble() { return b_has_rumble; }; bool has_deadzones();
bool has_deadzones() { return b_has_deadzones; };
pad_config* GetConfig() { return &m_pad_config; }; static std::string get_config_dir(pad_handler type);
static std::string get_config_filename(int i);
virtual bool Init() { return true; };
PadHandlerBase(pad_handler type = pad_handler::null);
virtual ~PadHandlerBase() = default;
//Sets window to config the controller(optional) //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 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 TestVibration(const std::string& /*padId*/, u32 /*largeMotor*/, u32 /*smallMotor*/) {};
//Return list of devices for that handler //Return list of devices for that handler
virtual std::vector<std::string> ListDevices() = 0; virtual std::vector<std::string> ListDevices() = 0;
//Callback called during pad_thread::ThreadFunc //Callback called during pad_thread::ThreadFunc
virtual void ThreadProc() = 0; virtual void ThreadProc() = 0;
//Binds a Pad to a device //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: 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) {};
protected:
void init_configs();
}; };

View File

@ -145,7 +145,6 @@ void fmt_class_string<video_aspect>::format(std::string& out, u64 arg)
}); });
} }
template <> template <>
void fmt_class_string<keyboard_handler>::format(std::string& out, u64 arg) void fmt_class_string<keyboard_handler>::format(std::string& out, u64 arg)
{ {

View File

@ -1,7 +1,4 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "ds4_pad_handler.h" #include "ds4_pad_handler.h"
#include "rpcs3qt/pad_settings_dialog.h"
#include <thread> #include <thread>
@ -82,8 +79,10 @@ namespace
} }
} }
ds4_pad_handler::ds4_pad_handler() : is_init(false) ds4_pad_handler::ds4_pad_handler() : PadHandlerBase(pad_handler::ds4)
{ {
init_configs();
// Define border values // Define border values
thumb_min = 0; thumb_min = 0;
thumb_max = 255; thumb_max = 255;
@ -92,52 +91,6 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false)
vibration_min = 0; vibration_min = 0;
vibration_max = 255; vibration_max = 255;
// Set this handler's type and save location
m_pad_config.cfg_type = "ds4";
m_pad_config.cfg_name = fs::get_config_dir() + "/config_ds4.yml";
// Set default button mapping
m_pad_config.ls_left.def = button_list.at(DS4KeyCodes::LSXNeg);
m_pad_config.ls_down.def = button_list.at(DS4KeyCodes::LSYNeg);
m_pad_config.ls_right.def = button_list.at(DS4KeyCodes::LSXPos);
m_pad_config.ls_up.def = button_list.at(DS4KeyCodes::LSYPos);
m_pad_config.rs_left.def = button_list.at(DS4KeyCodes::RSXNeg);
m_pad_config.rs_down.def = button_list.at(DS4KeyCodes::RSYNeg);
m_pad_config.rs_right.def = button_list.at(DS4KeyCodes::RSXPos);
m_pad_config.rs_up.def = button_list.at(DS4KeyCodes::RSYPos);
m_pad_config.start.def = button_list.at(DS4KeyCodes::Options);
m_pad_config.select.def = button_list.at(DS4KeyCodes::Share);
m_pad_config.ps.def = button_list.at(DS4KeyCodes::PSButton);
m_pad_config.square.def = button_list.at(DS4KeyCodes::Square);
m_pad_config.cross.def = button_list.at(DS4KeyCodes::Cross);
m_pad_config.circle.def = button_list.at(DS4KeyCodes::Circle);
m_pad_config.triangle.def = button_list.at(DS4KeyCodes::Triangle);
m_pad_config.left.def = button_list.at(DS4KeyCodes::Left);
m_pad_config.down.def = button_list.at(DS4KeyCodes::Down);
m_pad_config.right.def = button_list.at(DS4KeyCodes::Right);
m_pad_config.up.def = button_list.at(DS4KeyCodes::Up);
m_pad_config.r1.def = button_list.at(DS4KeyCodes::R1);
m_pad_config.r2.def = button_list.at(DS4KeyCodes::R2);
m_pad_config.r3.def = button_list.at(DS4KeyCodes::R3);
m_pad_config.l1.def = button_list.at(DS4KeyCodes::L1);
m_pad_config.l2.def = button_list.at(DS4KeyCodes::L2);
m_pad_config.l3.def = button_list.at(DS4KeyCodes::L3);
// Set default misc variables
m_pad_config.lstickdeadzone.def = 40; // between 0 and 255
m_pad_config.rstickdeadzone.def = 40; // between 0 and 255
m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255
m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255
m_pad_config.padsquircling.def = 8000;
// Set color value
m_pad_config.colorR.def = 0;
m_pad_config.colorG.def = 0;
m_pad_config.colorB.def = 20;
// apply defaults
m_pad_config.from_default();
// set capabilities // set capabilities
b_has_config = true; b_has_config = true;
b_has_rumble = true; b_has_rumble = true;
@ -147,6 +100,54 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false)
m_thumb_threshold = thumb_max / 2; m_thumb_threshold = thumb_max / 2;
} }
void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name)
{
// Set this profile's save location
cfg->cfg_name = name;
// Set default button mapping
cfg->ls_left.def = button_list.at(DS4KeyCodes::LSXNeg);
cfg->ls_down.def = button_list.at(DS4KeyCodes::LSYNeg);
cfg->ls_right.def = button_list.at(DS4KeyCodes::LSXPos);
cfg->ls_up.def = button_list.at(DS4KeyCodes::LSYPos);
cfg->rs_left.def = button_list.at(DS4KeyCodes::RSXNeg);
cfg->rs_down.def = button_list.at(DS4KeyCodes::RSYNeg);
cfg->rs_right.def = button_list.at(DS4KeyCodes::RSXPos);
cfg->rs_up.def = button_list.at(DS4KeyCodes::RSYPos);
cfg->start.def = button_list.at(DS4KeyCodes::Options);
cfg->select.def = button_list.at(DS4KeyCodes::Share);
cfg->ps.def = button_list.at(DS4KeyCodes::PSButton);
cfg->square.def = button_list.at(DS4KeyCodes::Square);
cfg->cross.def = button_list.at(DS4KeyCodes::Cross);
cfg->circle.def = button_list.at(DS4KeyCodes::Circle);
cfg->triangle.def = button_list.at(DS4KeyCodes::Triangle);
cfg->left.def = button_list.at(DS4KeyCodes::Left);
cfg->down.def = button_list.at(DS4KeyCodes::Down);
cfg->right.def = button_list.at(DS4KeyCodes::Right);
cfg->up.def = button_list.at(DS4KeyCodes::Up);
cfg->r1.def = button_list.at(DS4KeyCodes::R1);
cfg->r2.def = button_list.at(DS4KeyCodes::R2);
cfg->r3.def = button_list.at(DS4KeyCodes::R3);
cfg->l1.def = button_list.at(DS4KeyCodes::L1);
cfg->l2.def = button_list.at(DS4KeyCodes::L2);
cfg->l3.def = button_list.at(DS4KeyCodes::L3);
// Set default misc variables
cfg->lstickdeadzone.def = 40; // between 0 and 255
cfg->rstickdeadzone.def = 40; // between 0 and 255
cfg->ltriggerthreshold.def = 0; // between 0 and 255
cfg->rtriggerthreshold.def = 0; // between 0 and 255
cfg->padsquircling.def = 8000;
// Set color value
cfg->colorR.def = 0;
cfg->colorG.def = 0;
cfg->colorB.def = 20;
// apply defaults
cfg->from_default();
}
void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons) void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons)
{ {
if (get_blacklist) if (get_blacklist)
@ -227,6 +228,21 @@ void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u3
device->largeVibrate = largeMotor; device->largeVibrate = largeMotor;
device->smallVibrate = smallMotor; device->smallVibrate = smallMotor;
int index = 0;
for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (g_cfg_input.player[i]->handler == pad_handler::ds4)
{
if (g_cfg_input.player[i]->device.to_string() == padId)
{
m_pad_configs[index].load();
device->config = &m_pad_configs[index];
break;
}
index++;
}
}
// Start/Stop the engines :) // Start/Stop the engines :)
SendVibrateData(device); SendVibrateData(device);
} }
@ -259,29 +275,30 @@ void ds4_pad_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& val,
{ {
// Update the pad button values based on their type and thresholds. // Update the pad button values based on their type and thresholds.
// With this you can use axis or triggers as buttons or vice versa // With this you can use axis or triggers as buttons or vice versa
auto p_profile = m_dev->config;
switch (keyCode) switch (keyCode)
{ {
case DS4KeyCodes::L2: case DS4KeyCodes::L2:
pressed = val > m_pad_config.ltriggerthreshold; pressed = val > p_profile->ltriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0; val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0;
break; break;
case DS4KeyCodes::R2: case DS4KeyCodes::R2:
pressed = val > m_pad_config.rtriggerthreshold; pressed = val > p_profile->rtriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0; val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0;
break; break;
case DS4KeyCodes::LSXNeg: case DS4KeyCodes::LSXNeg:
case DS4KeyCodes::LSXPos: case DS4KeyCodes::LSXPos:
case DS4KeyCodes::LSYNeg: case DS4KeyCodes::LSYNeg:
case DS4KeyCodes::LSYPos: case DS4KeyCodes::LSYPos:
pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0; val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0;
break; break;
case DS4KeyCodes::RSXNeg: case DS4KeyCodes::RSXNeg:
case DS4KeyCodes::RSXPos: case DS4KeyCodes::RSXPos:
case DS4KeyCodes::RSYNeg: case DS4KeyCodes::RSYNeg:
case DS4KeyCodes::RSYPos: case DS4KeyCodes::RSYPos:
pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0; val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0;
break; break;
default: // normal button (should in theory also support sensitive buttons) default: // normal button (should in theory also support sensitive buttons)
pressed = val > 0; pressed = val > 0;
@ -406,8 +423,8 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr<DS4Device>& device,
pad->m_cable_state = device->cableState; pad->m_cable_state = device->cableState;
auto buf = device->padData; auto buf = device->padData;
auto button_values = GetButtonValues(device); auto button_values = GetButtonValues(device);
auto p_profile = device->config;
// Translate any corresponding keycodes to our normal DS3 buttons and triggers // Translate any corresponding keycodes to our normal DS3 buttons and triggers
for (auto & btn : pad->m_buttons) for (auto & btn : pad->m_buttons)
@ -428,7 +445,7 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr<DS4Device>& device,
#endif #endif
// used to get the absolute value of an axis // used to get the absolute value of an axis
float stick_val[4]; s32 stick_val[4];
// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++) for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++)
@ -452,13 +469,13 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr<DS4Device>& device,
u16 lx, ly, rx, ry; u16 lx, ly, rx, ry;
// Normalize our two stick's axis based on the thresholds // Normalize our two stick's axis based on the thresholds
std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], m_pad_config.lstickdeadzone); std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], p_profile->lstickdeadzone);
std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone); std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], p_profile->rstickdeadzone);
if (m_pad_config.padsquircling != 0) if (p_profile->padsquircling != 0)
{ {
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, p_profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, p_profile->padsquircling);
} }
ly = 255 - ly; ly = 255 - ly;
@ -654,6 +671,10 @@ ds4_pad_handler::~ds4_pad_handler()
int ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device>& device) int ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device>& device)
{ {
auto p_profile = device->config;
if (p_profile == nullptr)
return -2; // hid_write and hid_write_control return -1 on error
std::array<u8, 78> outputBuf{0}; std::array<u8, 78> outputBuf{0};
// write rumble state // write rumble state
if (device->btCon) if (device->btCon)
@ -663,9 +684,9 @@ int ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device>& device)
outputBuf[3] = 0x07; outputBuf[3] = 0x07;
outputBuf[6] = device->smallVibrate; outputBuf[6] = device->smallVibrate;
outputBuf[7] = device->largeVibrate; outputBuf[7] = device->largeVibrate;
outputBuf[8] = m_pad_config.colorR; // red outputBuf[8] = p_profile->colorR; // red
outputBuf[9] = m_pad_config.colorG; // green outputBuf[9] = p_profile->colorG; // green
outputBuf[10] = m_pad_config.colorB; // blue outputBuf[10] = p_profile->colorB; // blue
// alternating blink states with values 0-255: only setting both to zero disables blinking // alternating blink states with values 0-255: only setting both to zero disables blinking
// 255 is roughly 2 seconds, so setting both values to 255 results in a 4 second interval // 255 is roughly 2 seconds, so setting both values to 255 results in a 4 second interval
@ -690,9 +711,9 @@ int ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device>& device)
outputBuf[1] = 0x07; outputBuf[1] = 0x07;
outputBuf[4] = device->smallVibrate; outputBuf[4] = device->smallVibrate;
outputBuf[5] = device->largeVibrate; outputBuf[5] = device->largeVibrate;
outputBuf[6] = m_pad_config.colorR; // red outputBuf[6] = p_profile->colorR; // red
outputBuf[7] = m_pad_config.colorG; // green outputBuf[7] = p_profile->colorG; // green
outputBuf[8] = m_pad_config.colorB; // blue outputBuf[8] = p_profile->colorB; // blue
outputBuf[9] = device->led_delay_on; outputBuf[9] = device->led_delay_on;
outputBuf[10] = device->led_delay_off; outputBuf[10] = device->led_delay_off;
@ -734,10 +755,6 @@ bool ds4_pad_handler::Init()
else else
LOG_SUCCESS(HLE, "[DS4] Controllers found: %d", controllers.size()); LOG_SUCCESS(HLE, "[DS4] Controllers found: %d", controllers.size());
m_pad_config.load();
if (!m_pad_config.exist())
m_pad_config.save();
is_init = true; is_init = true;
return true; return true;
} }
@ -763,7 +780,12 @@ bool ds4_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::strin
if (ds4device == nullptr || ds4device->hidDevice == nullptr) if (ds4device == nullptr || ds4device->hidDevice == nullptr)
return false; return false;
m_pad_config.load(); int index = static_cast<int>(bindings.size());
m_pad_configs[index].load();
ds4device->config = &m_pad_configs[index];
pad_config* p_profile = ds4device->config;
if (p_profile == nullptr)
return false;
pad->Init pad->Init
( (
@ -774,34 +796,34 @@ bool ds4_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::strin
); );
// 'keycode' here is just 0 as we have to manually calculate this // 'keycode' here is just 0 as we have to manually calculate this
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l2), CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r2), CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.up), CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.down), CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.left), CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.right), CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.square), CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.cross), CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l1), CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r1), CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.select), CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.start), CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.l3), CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.r3), CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, m_pad_config.ls_left), FindKeyCode(button_list, m_pad_config.ls_right)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, m_pad_config.ls_down), FindKeyCode(button_list, m_pad_config.ls_up)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, m_pad_config.rs_left), FindKeyCode(button_list, m_pad_config.rs_right)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, m_pad_config.rs_down), FindKeyCode(button_list, m_pad_config.rs_up)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up));
pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0); pad->m_vibrateMotors.emplace_back(false, 0);
@ -815,13 +837,14 @@ void ds4_pad_handler::ThreadProc()
{ {
for (int i = 0; i < static_cast<int>(bindings.size()); i++) for (int i = 0; i < static_cast<int>(bindings.size()); i++)
{ {
std::shared_ptr<DS4Device> device = bindings[i].first; m_dev = bindings[i].first;
auto thepad = bindings[i].second; auto thepad = bindings[i].second;
auto profile = m_dev->config;
if (device->hidDevice == nullptr) if (m_dev->hidDevice == nullptr)
{ {
// try to reconnect // try to reconnect
hid_device* dev = hid_open_path(device->path.c_str()); hid_device* dev = hid_open_path(m_dev->path.c_str());
if (dev) if (dev)
{ {
if (last_connection_status[i] == false) if (last_connection_status[i] == false)
@ -831,10 +854,10 @@ void ds4_pad_handler::ThreadProc()
connected++; connected++;
} }
hid_set_nonblocking(dev, 1); hid_set_nonblocking(dev, 1);
device->hidDevice = dev; m_dev->hidDevice = dev;
thepad->m_port_status = CELL_PAD_STATUS_CONNECTED|CELL_PAD_STATUS_ASSIGN_CHANGES; thepad->m_port_status = CELL_PAD_STATUS_CONNECTED|CELL_PAD_STATUS_ASSIGN_CHANGES;
if (!device->hasCalibData) if (!m_dev->hasCalibData)
device->hasCalibData = GetCalibrationData(device); m_dev->hasCalibData = GetCalibrationData(m_dev);
} }
else else
{ {
@ -856,53 +879,53 @@ void ds4_pad_handler::ThreadProc()
connected++; connected++;
} }
DS4DataStatus status = GetRawData(device); DS4DataStatus status = GetRawData(m_dev);
if (status == DS4DataStatus::ReadError) if (status == DS4DataStatus::ReadError)
{ {
// this also can mean disconnected, either way deal with it on next loop and reconnect // this also can mean disconnected, either way deal with it on next loop and reconnect
hid_close(device->hidDevice); hid_close(m_dev->hidDevice);
device->hidDevice = nullptr; m_dev->hidDevice = nullptr;
continue; continue;
} }
// Attempt to send rumble no matter what // Attempt to send rumble no matter what
int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0; int idx_l = profile->switch_vibration_motors ? 1 : 0;
int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1; int idx_s = profile->switch_vibration_motors ? 0 : 1;
int speed_large = m_pad_config.enable_vibration_motor_large ? thepad->m_vibrateMotors[idx_l].m_value : vibration_min; int speed_large = profile->enable_vibration_motor_large ? thepad->m_vibrateMotors[idx_l].m_value : vibration_min;
int speed_small = m_pad_config.enable_vibration_motor_small ? thepad->m_vibrateMotors[idx_s].m_value : vibration_min; int speed_small = profile->enable_vibration_motor_small ? thepad->m_vibrateMotors[idx_s].m_value : vibration_min;
bool wireless = device->cableState < 1; bool wireless = m_dev->cableState < 1;
bool lowBattery = device->batteryLevel < 2; bool lowBattery = m_dev->batteryLevel < 2;
bool isBlinking = device->led_delay_on > 0 || device->led_delay_off > 0; bool isBlinking = m_dev->led_delay_on > 0 || m_dev->led_delay_off > 0;
bool newBlinkData = false; bool newBlinkData = false;
// we are now wired or have okay battery level -> stop blinking // we are now wired or have okay battery level -> stop blinking
if (isBlinking && !(wireless && lowBattery)) if (isBlinking && !(wireless && lowBattery))
{ {
device->led_delay_on = 0; m_dev->led_delay_on = 0;
device->led_delay_off = 0; m_dev->led_delay_off = 0;
newBlinkData = true; newBlinkData = true;
} }
// we are now wireless and low on battery -> blink // we are now wireless and low on battery -> blink
if (!isBlinking && wireless && lowBattery) if (!isBlinking && wireless && lowBattery)
{ {
device->led_delay_on = 100; m_dev->led_delay_on = 100;
device->led_delay_off = 100; m_dev->led_delay_off = 100;
newBlinkData = true; newBlinkData = true;
} }
device->newVibrateData = device->newVibrateData || device->largeVibrate != speed_large || device->smallVibrate != speed_small || newBlinkData; m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small || newBlinkData;
device->largeVibrate = speed_large; m_dev->largeVibrate = speed_large;
device->smallVibrate = speed_small; m_dev->smallVibrate = speed_small;
if (device->newVibrateData) if (m_dev->newVibrateData)
{ {
if (SendVibrateData(device) >= 0) if (SendVibrateData(m_dev) >= 0)
{ {
device->newVibrateData = false; m_dev->newVibrateData = false;
} }
} }
@ -911,7 +934,7 @@ void ds4_pad_handler::ThreadProc()
continue; continue;
else if (status == DS4DataStatus::NewData) else if (status == DS4DataStatus::NewData)
ProcessDataToPad(device, thepad); ProcessDataToPad(m_dev, thepad);
} }
} }

View File

@ -109,6 +109,7 @@ class ds4_pad_handler final : public PadHandlerBase
struct DS4Device struct DS4Device
{ {
hid_device* hidDevice{ nullptr }; hid_device* hidDevice{ nullptr };
pad_config* config{ nullptr };
std::string path{ "" }; std::string path{ "" };
bool btCon{ false }; bool btCon{ false };
bool hasCalibData{ false }; bool hasCalibData{ false };
@ -143,12 +144,14 @@ public:
void ThreadProc() override; void ThreadProc() override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& buttonCallback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& buttonCallback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
void init_config(pad_config* cfg, const std::string& name) override;
private: private:
bool is_init; bool is_init = false;
std::vector<u32> blacklist; std::vector<u32> blacklist;
std::vector<std::pair<std::shared_ptr<DS4Device>, std::shared_ptr<Pad>>> bindings; std::vector<std::pair<std::shared_ptr<DS4Device>, std::shared_ptr<Pad>>> bindings;
std::shared_ptr<DS4Device> m_dev;
private: private:
std::shared_ptr<DS4Device> GetDevice(const std::string& padId); std::shared_ptr<DS4Device> GetDevice(const std::string& padId);

View File

@ -123,6 +123,7 @@
<ClCompile Include="Emu\CPU\CPUTranslator.cpp"> <ClCompile Include="Emu\CPU\CPUTranslator.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Io\PadHandler.cpp" />
<ClCompile Include="Emu\PSP2\ARMv7Module.cpp" /> <ClCompile Include="Emu\PSP2\ARMv7Module.cpp" />
<ClCompile Include="Emu\Cell\lv2\lv2.cpp" /> <ClCompile Include="Emu\Cell\lv2\lv2.cpp" />
<ClCompile Include="Emu\Cell\lv2\sys_cond.cpp" /> <ClCompile Include="Emu\Cell\lv2\sys_cond.cpp" />

View File

@ -935,6 +935,9 @@
<ClCompile Include="Emu\Cell\lv2\sys_net.cpp"> <ClCompile Include="Emu\Cell\lv2\sys_net.cpp">
<Filter>Emu\Cell\lv2</Filter> <Filter>Emu\Cell\lv2</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Io\PadHandler.cpp">
<Filter>Emu\Io</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">

View File

@ -17,8 +17,10 @@
#include <cstdio> #include <cstdio>
#include <cmath> #include <cmath>
evdev_joystick_handler::evdev_joystick_handler() evdev_joystick_handler::evdev_joystick_handler() : PadHandlerBase(pad_handler::evdev)
{ {
init_configs();
// Define border values // Define border values
thumb_min = 0; thumb_min = 0;
thumb_max = 255; thumb_max = 255;
@ -27,47 +29,6 @@ evdev_joystick_handler::evdev_joystick_handler()
vibration_min = 0; vibration_min = 0;
vibration_max = 65535; vibration_max = 65535;
// Set this handler's type and save location
m_pad_config.cfg_type = "evdev";
m_pad_config.cfg_name = fs::get_config_dir() + "/config_evdev.yml";
// Set default button mapping
m_pad_config.ls_left.def = rev_axis_list.at(ABS_X);
m_pad_config.ls_down.def = axis_list.at(ABS_Y);
m_pad_config.ls_right.def = axis_list.at(ABS_X);
m_pad_config.ls_up.def = rev_axis_list.at(ABS_Y);
m_pad_config.rs_left.def = rev_axis_list.at(ABS_RX);
m_pad_config.rs_down.def = axis_list.at(ABS_RY);
m_pad_config.rs_right.def = axis_list.at(ABS_RX);
m_pad_config.rs_up.def = rev_axis_list.at(ABS_RY);
m_pad_config.start.def = button_list.at(BTN_START);
m_pad_config.select.def = button_list.at(BTN_SELECT);
m_pad_config.ps.def = button_list.at(BTN_MODE);
m_pad_config.square.def = button_list.at(BTN_X);
m_pad_config.cross.def = button_list.at(BTN_A);
m_pad_config.circle.def = button_list.at(BTN_B);
m_pad_config.triangle.def = button_list.at(BTN_Y);
m_pad_config.left.def = rev_axis_list.at(ABS_HAT0X);
m_pad_config.down.def = axis_list.at(ABS_HAT0Y);
m_pad_config.right.def = axis_list.at(ABS_HAT0X);
m_pad_config.up.def = rev_axis_list.at(ABS_HAT0Y);
m_pad_config.r1.def = button_list.at(BTN_TR);
m_pad_config.r2.def = axis_list.at(ABS_RZ);
m_pad_config.r3.def = button_list.at(BTN_THUMBR);
m_pad_config.l1.def = button_list.at(BTN_TL);
m_pad_config.l2.def = axis_list.at(ABS_Z);
m_pad_config.l3.def = button_list.at(BTN_THUMBL);
// Set default misc variables
m_pad_config.lstickdeadzone.def = 30; // between 0 and 255
m_pad_config.rstickdeadzone.def = 30; // between 0 and 255
m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255
m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255
m_pad_config.padsquircling.def = 5000;
// apply defaults
m_pad_config.from_default();
// set capabilities // set capabilities
b_has_config = true; b_has_config = true;
b_has_rumble = true; b_has_rumble = true;
@ -82,12 +43,54 @@ evdev_joystick_handler::~evdev_joystick_handler()
Close(); Close();
} }
void evdev_joystick_handler::init_config(pad_config* cfg, const std::string& name)
{
// Set this profile's save location
cfg->cfg_name = name;
// Set default button mapping
cfg->ls_left.def = rev_axis_list.at(ABS_X);
cfg->ls_down.def = axis_list.at(ABS_Y);
cfg->ls_right.def = axis_list.at(ABS_X);
cfg->ls_up.def = rev_axis_list.at(ABS_Y);
cfg->rs_left.def = rev_axis_list.at(ABS_RX);
cfg->rs_down.def = axis_list.at(ABS_RY);
cfg->rs_right.def = axis_list.at(ABS_RX);
cfg->rs_up.def = rev_axis_list.at(ABS_RY);
cfg->start.def = button_list.at(BTN_START);
cfg->select.def = button_list.at(BTN_SELECT);
cfg->ps.def = button_list.at(BTN_MODE);
cfg->square.def = button_list.at(BTN_X);
cfg->cross.def = button_list.at(BTN_A);
cfg->circle.def = button_list.at(BTN_B);
cfg->triangle.def = button_list.at(BTN_Y);
cfg->left.def = rev_axis_list.at(ABS_HAT0X);
cfg->down.def = axis_list.at(ABS_HAT0Y);
cfg->right.def = axis_list.at(ABS_HAT0X);
cfg->up.def = rev_axis_list.at(ABS_HAT0Y);
cfg->r1.def = button_list.at(BTN_TR);
cfg->r2.def = axis_list.at(ABS_RZ);
cfg->r3.def = button_list.at(BTN_THUMBR);
cfg->l1.def = button_list.at(BTN_TL);
cfg->l2.def = axis_list.at(ABS_Z);
cfg->l3.def = button_list.at(BTN_THUMBL);
// Set default misc variables
cfg->lstickdeadzone.def = 30; // between 0 and 255
cfg->rstickdeadzone.def = 30; // between 0 and 255
cfg->ltriggerthreshold.def = 0; // between 0 and 255
cfg->rtriggerthreshold.def = 0; // between 0 and 255
cfg->padsquircling.def = 5000;
// apply defaults
cfg->from_default();
}
bool evdev_joystick_handler::Init() bool evdev_joystick_handler::Init()
{ {
if (m_is_init) if (m_is_init)
return true; return true;
m_pad_config.load();
m_pos_axis_config.load(); m_pos_axis_config.load();
if (!m_pos_axis_config.exist()) if (!m_pos_axis_config.exist())
@ -498,6 +501,7 @@ void evdev_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u1
{ {
// Update the pad button values based on their type and thresholds. // Update the pad button values based on their type and thresholds.
// With this you can use axis or triggers as buttons or vice versa // With this you can use axis or triggers as buttons or vice versa
auto profile = m_dev.config;
u32 code = static_cast<u32>(keyCode); u32 code = static_cast<u32>(keyCode);
auto checkButton = [&](const EvdevButton& b) auto checkButton = [&](const EvdevButton& b)
{ {
@ -510,23 +514,23 @@ void evdev_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u1
if (checkButton(m_dev.trigger_left)) if (checkButton(m_dev.trigger_left))
{ {
pressed = value > m_pad_config.ltriggerthreshold; pressed = value > profile->ltriggerthreshold;
value = pressed ? NormalizeTriggerInput(value, m_pad_config.ltriggerthreshold) : 0; value = pressed ? NormalizeTriggerInput(value, profile->ltriggerthreshold) : 0;
} }
else if (checkButton(m_dev.trigger_right)) else if (checkButton(m_dev.trigger_right))
{ {
pressed = value > m_pad_config.rtriggerthreshold; pressed = value > profile->rtriggerthreshold;
value = pressed ? NormalizeTriggerInput(value, m_pad_config.rtriggerthreshold) : 0; value = pressed ? NormalizeTriggerInput(value, profile->rtriggerthreshold) : 0;
} }
else if (checkButtons(m_dev.axis_left)) else if (checkButtons(m_dev.axis_left))
{ {
pressed = value > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); pressed = value > (ignore_threshold ? 0 : profile->lstickdeadzone);
value = pressed ? NormalizeStickInput(value, m_pad_config.lstickdeadzone, ignore_threshold) : 0; value = pressed ? NormalizeStickInput(value, profile->lstickdeadzone, ignore_threshold) : 0;
} }
else if (checkButtons(m_dev.axis_right)) else if (checkButtons(m_dev.axis_right))
{ {
pressed = value > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); pressed = value > (ignore_threshold ? 0 : profile->rstickdeadzone);
value = pressed ? NormalizeStickInput(value, m_pad_config.rstickdeadzone, ignore_threshold) : 0; value = pressed ? NormalizeStickInput(value, profile->rstickdeadzone, ignore_threshold) : 0;
} }
else // normal button (should in theory also support sensitive buttons) else // normal button (should in theory also support sensitive buttons)
{ {
@ -608,7 +612,7 @@ std::vector<std::string> evdev_joystick_handler::ListDevices()
libevdev_has_event_code(dev, EV_ABS, ABS_Y)) libevdev_has_event_code(dev, EV_ABS, ABS_Y))
{ {
// It's a joystick. // It's a joystick.
evdev_joystick_list.push_back(libevdev_get_name(dev)); evdev_joystick_list.push_back(et.name + ": " + libevdev_get_name(dev));
} }
libevdev_free(dev); libevdev_free(dev);
close(fd); close(fd);
@ -643,7 +647,7 @@ int evdev_joystick_handler::add_device(const std::string& device, bool in_settin
close(fd); close(fd);
continue; continue;
} }
const std::string name = libevdev_get_name(dev); const std::string name = et.name + ": " + libevdev_get_name(dev);
if (libevdev_has_event_type(dev, EV_KEY) && if (libevdev_has_event_type(dev, EV_KEY) &&
libevdev_has_event_code(dev, EV_ABS, ABS_X) && libevdev_has_event_code(dev, EV_ABS, ABS_X) &&
libevdev_has_event_code(dev, EV_ABS, ABS_Y) && libevdev_has_event_code(dev, EV_ABS, ABS_Y) &&
@ -680,6 +684,7 @@ void evdev_joystick_handler::ThreadProc()
for (auto& device : devices) for (auto& device : devices)
{ {
m_dev = device; m_dev = device;
auto profile = device.config;
auto pad = device.pad; auto pad = device.pad;
auto axis_orientations = device.axis_orientations; auto axis_orientations = device.axis_orientations;
auto& dev = device.device; auto& dev = device.device;
@ -704,10 +709,10 @@ void evdev_joystick_handler::ThreadProc()
padnum++; padnum++;
// Handle vibration // Handle vibration
int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0; int idx_l = profile->switch_vibration_motors ? 1 : 0;
int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1; int idx_s = profile->switch_vibration_motors ? 0 : 1;
u16 force_large = m_pad_config.enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; u16 force_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min;
u16 force_small = m_pad_config.enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; u16 force_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min;
SetRumble(&device, force_large, force_small); SetRumble(&device, force_large, force_small);
// Try to query the latest event from the joystick. // Try to query the latest event from the joystick.
@ -832,13 +837,13 @@ void evdev_joystick_handler::ThreadProc()
u16 lx, ly, rx, ry; u16 lx, ly, rx, ry;
// Normalize our two stick's axis based on the thresholds // Normalize our two stick's axis based on the thresholds
std::tie(lx, ly) = NormalizeStickDeadzone(device.stick_val[0], device.stick_val[1], m_pad_config.lstickdeadzone); std::tie(lx, ly) = NormalizeStickDeadzone(device.stick_val[0], device.stick_val[1], profile->lstickdeadzone);
std::tie(rx, ry) = NormalizeStickDeadzone(device.stick_val[2], device.stick_val[3], m_pad_config.rstickdeadzone); std::tie(rx, ry) = NormalizeStickDeadzone(device.stick_val[2], device.stick_val[3], profile->rstickdeadzone);
if (m_pad_config.padsquircling != 0) if (profile->padsquircling != 0)
{ {
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
} }
pad->m_sticks[0].m_value = lx; pad->m_sticks[0].m_value = lx;
@ -866,6 +871,13 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std
int i = 0; // increment to know the axis location (17-24). Be careful if you ever add more find_key() calls in here (BUTTON_COUNT = 17) int i = 0; // increment to know the axis location (17-24). Be careful if you ever add more find_key() calls in here (BUTTON_COUNT = 17)
int last_type = EV_ABS; int last_type = EV_ABS;
int index = static_cast<int>(devices.size());
m_pad_configs[index].load();
m_dev.config = &m_pad_configs[index];
pad_config* p_profile = m_dev.config;
if (p_profile == nullptr)
return false;
auto find_key = [&](const cfg::string& name) auto find_key = [&](const cfg::string& name)
{ {
int type = EV_ABS; int type = EV_ABS;
@ -909,38 +921,38 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std
CELL_PAD_DEV_TYPE_STANDARD CELL_PAD_DEV_TYPE_STANDARD
); );
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.cross), CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.square), CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE);
m_dev.trigger_left = evdevbutton(m_pad_config.l2); m_dev.trigger_left = evdevbutton(p_profile->l2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_left.code, CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_left.code, CELL_PAD_CTRL_L2);
m_dev.trigger_right = evdevbutton(m_pad_config.r2); m_dev.trigger_right = evdevbutton(p_profile->r2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_right.code, CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_right.code, CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l1), CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r1), CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.start), CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.select), CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.l3), CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.r3), CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.up), CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.down), CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.left), CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.right), CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
m_dev.axis_left[0] = evdevbutton(m_pad_config.ls_right); m_dev.axis_left[0] = evdevbutton(p_profile->ls_right);
m_dev.axis_left[1] = evdevbutton(m_pad_config.ls_left); m_dev.axis_left[1] = evdevbutton(p_profile->ls_left);
m_dev.axis_left[2] = evdevbutton(m_pad_config.ls_up); m_dev.axis_left[2] = evdevbutton(p_profile->ls_up);
m_dev.axis_left[3] = evdevbutton(m_pad_config.ls_down); m_dev.axis_left[3] = evdevbutton(p_profile->ls_down);
m_dev.axis_right[0] = evdevbutton(m_pad_config.rs_right); m_dev.axis_right[0] = evdevbutton(p_profile->rs_right);
m_dev.axis_right[1] = evdevbutton(m_pad_config.rs_left); m_dev.axis_right[1] = evdevbutton(p_profile->rs_left);
m_dev.axis_right[2] = evdevbutton(m_pad_config.rs_up); m_dev.axis_right[2] = evdevbutton(p_profile->rs_up);
m_dev.axis_right[3] = evdevbutton(m_pad_config.rs_down); m_dev.axis_right[3] = evdevbutton(p_profile->rs_down);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev.axis_left[1].code, m_dev.axis_left[0].code); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev.axis_left[1].code, m_dev.axis_left[0].code);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev.axis_left[3].code, m_dev.axis_left[2].code); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev.axis_left[3].code, m_dev.axis_left[2].code);

View File

@ -302,11 +302,12 @@ class evdev_joystick_handler final : public PadHandlerBase
struct EvdevDevice struct EvdevDevice
{ {
libevdev* device = nullptr; libevdev* device{ nullptr };
pad_config* config{ nullptr };
std::string path; std::string path;
std::shared_ptr<Pad> pad; std::shared_ptr<Pad> pad;
std::unordered_map<int, bool> axis_orientations; // value is true if key was found in rev_axis_list std::unordered_map<int, bool> axis_orientations; // value is true if key was found in rev_axis_list
float stick_val[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; s32 stick_val[4] = { 0, 0, 0, 0 };
u16 val_min[4] = { 0, 0, 0, 0 }; u16 val_min[4] = { 0, 0, 0, 0 };
u16 val_max[4] = { 0, 0, 0, 0 }; u16 val_max[4] = { 0, 0, 0, 0 };
EvdevButton trigger_left = { 0, 0, 0 }; EvdevButton trigger_left = { 0, 0, 0 };
@ -328,6 +329,7 @@ public:
evdev_joystick_handler(); evdev_joystick_handler();
~evdev_joystick_handler(); ~evdev_joystick_handler();
void init_config(pad_config* cfg, const std::string& name) override;
bool Init() override; bool Init() override;
std::vector<std::string> ListDevices() override; std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;

View File

@ -1,11 +1,7 @@
#include "stdafx.h" #include "keyboard_pad_handler.h"
#include "keyboard_pad_handler.h"
#include <QApplication> #include <QApplication>
#include "rpcs3qt/pad_settings_dialog.h"
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString; constexpr auto qstr = QString::fromStdString;
@ -14,46 +10,50 @@ bool keyboard_pad_handler::Init()
return true; return true;
} }
keyboard_pad_handler::keyboard_pad_handler() : QObject() keyboard_pad_handler::keyboard_pad_handler() : PadHandlerBase(pad_handler::keyboard), QObject()
{ {
// Set this handler's type and save location init_configs();
m_pad_config.cfg_type = "keyboard";
m_pad_config.cfg_name = fs::get_config_dir() + "/config_kbpad_qt.yml";
// Set default button mapping
m_pad_config.ls_left.def = GetKeyName(Qt::Key_A);
m_pad_config.ls_down.def = GetKeyName(Qt::Key_S);
m_pad_config.ls_right.def = GetKeyName(Qt::Key_D);
m_pad_config.ls_up.def = GetKeyName(Qt::Key_W);
m_pad_config.rs_left.def = GetKeyName(Qt::Key_Home);
m_pad_config.rs_down.def = GetKeyName(Qt::Key_PageDown);
m_pad_config.rs_right.def = GetKeyName(Qt::Key_End);
m_pad_config.rs_up.def = GetKeyName(Qt::Key_PageUp);
m_pad_config.start.def = GetKeyName(Qt::Key_Return);
m_pad_config.select.def = GetKeyName(Qt::Key_Space);
m_pad_config.ps.def = GetKeyName(Qt::Key_Backspace);
m_pad_config.square.def = GetKeyName(Qt::Key_Z);
m_pad_config.cross.def = GetKeyName(Qt::Key_X);
m_pad_config.circle.def = GetKeyName(Qt::Key_C);
m_pad_config.triangle.def = GetKeyName(Qt::Key_V);
m_pad_config.left.def = GetKeyName(Qt::Key_Left);
m_pad_config.down.def = GetKeyName(Qt::Key_Down);
m_pad_config.right.def = GetKeyName(Qt::Key_Right);
m_pad_config.up.def = GetKeyName(Qt::Key_Up);
m_pad_config.r1.def = GetKeyName(Qt::Key_E);
m_pad_config.r2.def = GetKeyName(Qt::Key_T);
m_pad_config.r3.def = GetKeyName(Qt::Key_G);
m_pad_config.l1.def = GetKeyName(Qt::Key_Q);
m_pad_config.l2.def = GetKeyName(Qt::Key_R);
m_pad_config.l3.def = GetKeyName(Qt::Key_F);
// apply defaults
m_pad_config.from_default();
// set capabilities // set capabilities
b_has_config = true; b_has_config = true;
} }
void keyboard_pad_handler::init_config(pad_config* cfg, const std::string& name)
{
// Set this profile's save location
cfg->cfg_name = name;
// Set default button mapping
cfg->ls_left.def = GetKeyName(Qt::Key_A);
cfg->ls_down.def = GetKeyName(Qt::Key_S);
cfg->ls_right.def = GetKeyName(Qt::Key_D);
cfg->ls_up.def = GetKeyName(Qt::Key_W);
cfg->rs_left.def = GetKeyName(Qt::Key_Home);
cfg->rs_down.def = GetKeyName(Qt::Key_PageDown);
cfg->rs_right.def = GetKeyName(Qt::Key_End);
cfg->rs_up.def = GetKeyName(Qt::Key_PageUp);
cfg->start.def = GetKeyName(Qt::Key_Return);
cfg->select.def = GetKeyName(Qt::Key_Space);
cfg->ps.def = GetKeyName(Qt::Key_Backspace);
cfg->square.def = GetKeyName(Qt::Key_Z);
cfg->cross.def = GetKeyName(Qt::Key_X);
cfg->circle.def = GetKeyName(Qt::Key_C);
cfg->triangle.def = GetKeyName(Qt::Key_V);
cfg->left.def = GetKeyName(Qt::Key_Left);
cfg->down.def = GetKeyName(Qt::Key_Down);
cfg->right.def = GetKeyName(Qt::Key_Right);
cfg->up.def = GetKeyName(Qt::Key_Up);
cfg->r1.def = GetKeyName(Qt::Key_E);
cfg->r2.def = GetKeyName(Qt::Key_T);
cfg->r3.def = GetKeyName(Qt::Key_G);
cfg->l1.def = GetKeyName(Qt::Key_Q);
cfg->l2.def = GetKeyName(Qt::Key_R);
cfg->l3.def = GetKeyName(Qt::Key_F);
// apply defaults
cfg->from_default();
}
void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
{ {
value = Clamp0To255(value); value = Clamp0To255(value);
@ -65,30 +65,23 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
if (button.m_keyCode != code) if (button.m_keyCode != code)
continue; continue;
//Todo: Is this flush necessary once games hit decent speeds? button.m_pressed = pressed;
if (button.m_pressed && !pressed) button.m_value = pressed ? value : 0;
{
button.m_flush = true;
}
else
{
button.m_pressed = pressed;
if (pressed)
button.m_value = value;
else
button.m_value = 0;
}
} }
for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++) for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++)
{ {
if (pad->m_sticks[i].m_keyCodeMax == code) bool is_max = pad->m_sticks[i].m_keyCodeMax == code;
bool is_min = pad->m_sticks[i].m_keyCodeMin == code;
if (is_max)
m_stick_max[i] = pressed ? 255 : 128; m_stick_max[i] = pressed ? 255 : 128;
if (pad->m_sticks[i].m_keyCodeMin == code) if (is_min)
m_stick_min[i] = pressed ? 128 : 0; m_stick_min[i] = pressed ? 128 : 0;
pad->m_sticks[i].m_value = m_stick_max[i] - m_stick_min[i]; if (is_max || is_min)
pad->m_sticks[i].m_value = m_stick_max[i] - m_stick_min[i];
} }
} }
} }
@ -386,7 +379,11 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::
if (device != "Keyboard") if (device != "Keyboard")
return false; return false;
m_pad_config.load(); int index = static_cast<int>(bindings.size());
m_pad_configs[index].load();
pad_config* p_profile = &m_pad_configs[index];
if (p_profile == nullptr)
return false;
auto find_key = [&](const cfg::string& name) auto find_key = [&](const cfg::string& name)
{ {
@ -407,29 +404,29 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::
CELL_PAD_DEV_TYPE_STANDARD CELL_PAD_DEV_TYPE_STANDARD
); );
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.left), CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.down), CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.right), CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.up), CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.start), CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.r3), CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.l3), CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.select), CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.square), CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.cross), CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r1), CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l1), CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r2), CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r2), CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l2), CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l2), CELL_PAD_CTRL_L2);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(m_pad_config.ls_left), find_key(m_pad_config.ls_right)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(p_profile->ls_left), find_key(p_profile->ls_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(m_pad_config.ls_up), find_key(m_pad_config.ls_down)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(p_profile->ls_up), find_key(p_profile->ls_down));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(m_pad_config.rs_left), find_key(m_pad_config.rs_right)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(p_profile->rs_left), find_key(p_profile->rs_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(m_pad_config.rs_up), find_key(m_pad_config.rs_down)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(p_profile->rs_up), find_key(p_profile->rs_down));
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399);

View File

@ -2,8 +2,6 @@
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "Emu/Io/PadHandler.h" #include "Emu/Io/PadHandler.h"
#include "stdafx.h"
#include "Emu/System.h"
#include <QWindow> #include <QWindow>
#include <QKeyEvent> #include <QKeyEvent>
@ -57,6 +55,7 @@ public:
bool eventFilter(QObject* obj, QEvent* ev) override; bool eventFilter(QObject* obj, QEvent* ev) override;
void init_config(pad_config* cfg, const std::string& name) override;
std::vector<std::string> ListDevices() override; std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override; void ThreadProc() override;

View File

@ -1,9 +1,10 @@
#include "stdafx.h"
#ifdef _WIN32 #ifdef _WIN32
#include "mm_joystick_handler.h" #include "mm_joystick_handler.h"
mm_joystick_handler::mm_joystick_handler() : is_init(false) mm_joystick_handler::mm_joystick_handler() : PadHandlerBase(pad_handler::mm)
{ {
init_configs();
// Define border values // Define border values
thumb_min = 0; thumb_min = 0;
thumb_max = 255; thumb_max = 255;
@ -12,47 +13,6 @@ mm_joystick_handler::mm_joystick_handler() : is_init(false)
vibration_min = 0; vibration_min = 0;
vibration_max = 65535; vibration_max = 65535;
// Set this handler's type and save location
m_pad_config.cfg_type = "mmjoystick";
m_pad_config.cfg_name = fs::get_config_dir() + "/config_mmjoystick.yml";
// Set default button mapping
m_pad_config.ls_left.def = axis_list.at(mmjoy_axis::joy_x_neg);
m_pad_config.ls_down.def = axis_list.at(mmjoy_axis::joy_y_neg);
m_pad_config.ls_right.def = axis_list.at(mmjoy_axis::joy_x_pos);
m_pad_config.ls_up.def = axis_list.at(mmjoy_axis::joy_y_pos);
m_pad_config.rs_left.def = axis_list.at(mmjoy_axis::joy_z_neg);
m_pad_config.rs_down.def = axis_list.at(mmjoy_axis::joy_r_neg);
m_pad_config.rs_right.def = axis_list.at(mmjoy_axis::joy_z_pos);
m_pad_config.rs_up.def = axis_list.at(mmjoy_axis::joy_r_pos);
m_pad_config.start.def = button_list.at(JOY_BUTTON9);
m_pad_config.select.def = button_list.at(JOY_BUTTON10);
m_pad_config.ps.def = button_list.at(JOY_BUTTON17);
m_pad_config.square.def = button_list.at(JOY_BUTTON4);
m_pad_config.cross.def = button_list.at(JOY_BUTTON3);
m_pad_config.circle.def = button_list.at(JOY_BUTTON2);
m_pad_config.triangle.def = button_list.at(JOY_BUTTON1);
m_pad_config.left.def = pov_list.at(JOY_POVLEFT);
m_pad_config.down.def = pov_list.at(JOY_POVBACKWARD);
m_pad_config.right.def = pov_list.at(JOY_POVRIGHT);
m_pad_config.up.def = pov_list.at(JOY_POVFORWARD);
m_pad_config.r1.def = button_list.at(JOY_BUTTON8);
m_pad_config.r2.def = button_list.at(JOY_BUTTON6);
m_pad_config.r3.def = button_list.at(JOY_BUTTON12);
m_pad_config.l1.def = button_list.at(JOY_BUTTON7);
m_pad_config.l2.def = button_list.at(JOY_BUTTON5);
m_pad_config.l3.def = button_list.at(JOY_BUTTON11);
// Set default misc variables
m_pad_config.lstickdeadzone.def = 0; // between 0 and 255
m_pad_config.rstickdeadzone.def = 0; // between 0 and 255
m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255
m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255
m_pad_config.padsquircling.def = 8000;
// apply defaults
m_pad_config.from_default();
// set capabilities // set capabilities
b_has_config = true; b_has_config = true;
b_has_rumble = true; b_has_rumble = true;
@ -66,24 +26,66 @@ mm_joystick_handler::~mm_joystick_handler()
{ {
} }
void mm_joystick_handler::init_config(pad_config* cfg, const std::string& name)
{
// Set this profile's save location
cfg->cfg_name = name;
// Set default button mapping
cfg->ls_left.def = axis_list.at(mmjoy_axis::joy_x_neg);
cfg->ls_down.def = axis_list.at(mmjoy_axis::joy_y_neg);
cfg->ls_right.def = axis_list.at(mmjoy_axis::joy_x_pos);
cfg->ls_up.def = axis_list.at(mmjoy_axis::joy_y_pos);
cfg->rs_left.def = axis_list.at(mmjoy_axis::joy_z_neg);
cfg->rs_down.def = axis_list.at(mmjoy_axis::joy_r_neg);
cfg->rs_right.def = axis_list.at(mmjoy_axis::joy_z_pos);
cfg->rs_up.def = axis_list.at(mmjoy_axis::joy_r_pos);
cfg->start.def = button_list.at(JOY_BUTTON9);
cfg->select.def = button_list.at(JOY_BUTTON10);
cfg->ps.def = button_list.at(JOY_BUTTON17);
cfg->square.def = button_list.at(JOY_BUTTON4);
cfg->cross.def = button_list.at(JOY_BUTTON3);
cfg->circle.def = button_list.at(JOY_BUTTON2);
cfg->triangle.def = button_list.at(JOY_BUTTON1);
cfg->left.def = pov_list.at(JOY_POVLEFT);
cfg->down.def = pov_list.at(JOY_POVBACKWARD);
cfg->right.def = pov_list.at(JOY_POVRIGHT);
cfg->up.def = pov_list.at(JOY_POVFORWARD);
cfg->r1.def = button_list.at(JOY_BUTTON8);
cfg->r2.def = button_list.at(JOY_BUTTON6);
cfg->r3.def = button_list.at(JOY_BUTTON12);
cfg->l1.def = button_list.at(JOY_BUTTON7);
cfg->l2.def = button_list.at(JOY_BUTTON5);
cfg->l3.def = button_list.at(JOY_BUTTON11);
// Set default misc variables
cfg->lstickdeadzone.def = 0; // between 0 and 255
cfg->rstickdeadzone.def = 0; // between 0 and 255
cfg->ltriggerthreshold.def = 0; // between 0 and 255
cfg->rtriggerthreshold.def = 0; // between 0 and 255
cfg->padsquircling.def = 8000;
// apply defaults
cfg->from_default();
}
bool mm_joystick_handler::Init() bool mm_joystick_handler::Init()
{ {
if (is_init) return true; if (is_init)
return true;
m_devices.clear(); m_devices.clear();
supportedJoysticks = joyGetNumDevs(); m_supported_joysticks = joyGetNumDevs();
if (supportedJoysticks > 0) if (m_supported_joysticks <= 0)
{ {
LOG_NOTICE(GENERAL, "Driver supports %u joysticks", supportedJoysticks); LOG_ERROR(GENERAL, "mmjoy: Driver doesn't support Joysticks");
}
else
{
LOG_ERROR(GENERAL, "Driver doesn't support Joysticks");
return false; return false;
} }
for (u32 i = 0; i < supportedJoysticks; i++) LOG_NOTICE(GENERAL, "mmjoy: Driver supports %u joysticks", m_supported_joysticks);
for (u32 i = 0; i < m_supported_joysticks; i++)
{ {
MMJOYDevice dev; MMJOYDevice dev;
@ -93,7 +95,6 @@ bool mm_joystick_handler::Init()
m_devices.emplace(i, dev); m_devices.emplace(i, dev);
} }
m_pad_config.load();
is_init = true; is_init = true;
return true; return true;
} }
@ -102,7 +103,8 @@ std::vector<std::string> mm_joystick_handler::ListDevices()
{ {
std::vector<std::string> devices; std::vector<std::string> devices;
if (!Init()) return devices; if (!Init())
return devices;
for (auto dev : m_devices) for (auto dev : m_devices)
{ {
@ -123,6 +125,13 @@ bool mm_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::s
std::shared_ptr<MMJOYDevice> joy_device = std::make_shared<MMJOYDevice>(m_devices.at(id)); std::shared_ptr<MMJOYDevice> joy_device = std::make_shared<MMJOYDevice>(m_devices.at(id));
int index = static_cast<int>(bindings.size());
m_pad_configs[index].load();
joy_device->config = &m_pad_configs[index];
pad_config* p_profile = joy_device->config;
if (p_profile == nullptr)
return false;
auto find_key = [=](const cfg::string& name) auto find_key = [=](const cfg::string& name)
{ {
long key = FindKeyCode(button_list, name, false); long key = FindKeyCode(button_list, name, false);
@ -141,34 +150,34 @@ bool mm_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::s
CELL_PAD_DEV_TYPE_STANDARD CELL_PAD_DEV_TYPE_STANDARD
); );
joy_device->trigger_left = find_key(m_pad_config.l2); joy_device->trigger_left = find_key(p_profile->l2);
joy_device->trigger_right = find_key(m_pad_config.r2); joy_device->trigger_right = find_key(p_profile->r2);
joy_device->axis_left[0] = find_key(m_pad_config.ls_left); joy_device->axis_left[0] = find_key(p_profile->ls_left);
joy_device->axis_left[1] = find_key(m_pad_config.ls_right); joy_device->axis_left[1] = find_key(p_profile->ls_right);
joy_device->axis_left[2] = find_key(m_pad_config.ls_down); joy_device->axis_left[2] = find_key(p_profile->ls_down);
joy_device->axis_left[3] = find_key(m_pad_config.ls_up); joy_device->axis_left[3] = find_key(p_profile->ls_up);
joy_device->axis_right[0] = find_key(m_pad_config.rs_left); joy_device->axis_right[0] = find_key(p_profile->rs_left);
joy_device->axis_right[1] = find_key(m_pad_config.rs_right); joy_device->axis_right[1] = find_key(p_profile->rs_right);
joy_device->axis_right[2] = find_key(m_pad_config.rs_down); joy_device->axis_right[2] = find_key(p_profile->rs_down);
joy_device->axis_right[3] = find_key(m_pad_config.rs_up); joy_device->axis_right[3] = find_key(p_profile->rs_up);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.cross), CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.square), CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_left, CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_left, CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_right, CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_right, CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l1), CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r1), CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.start), CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.select), CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.l3), CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.r3), CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.up), CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.down), CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.left), CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.right), CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, joy_device->axis_left[0], joy_device->axis_left[1]); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, joy_device->axis_left[0], joy_device->axis_left[1]);
@ -197,6 +206,7 @@ void mm_joystick_handler::ThreadProc()
{ {
m_dev = bindings[i].first; m_dev = bindings[i].first;
auto pad = bindings[i].second; auto pad = bindings[i].second;
auto profile = m_dev->config;
status = joyGetPosEx(m_dev->device_id, &m_dev->device_info); status = joyGetPosEx(m_dev->device_id, &m_dev->device_info);
if (status != JOYERR_NOERROR) if (status != JOYERR_NOERROR)
@ -232,7 +242,7 @@ void mm_joystick_handler::ThreadProc()
TranslateButtonPress(btn.m_keyCode, btn.m_pressed, btn.m_value); TranslateButtonPress(btn.m_keyCode, btn.m_pressed, btn.m_value);
} }
float stick_val[4]; s32 stick_val[4];
// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++) for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++)
@ -256,13 +266,13 @@ void mm_joystick_handler::ThreadProc()
u16 lx, ly, rx, ry; u16 lx, ly, rx, ry;
// Normalize our two stick's axis based on the thresholds // Normalize our two stick's axis based on the thresholds
std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], m_pad_config.lstickdeadzone); std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone);
std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone); std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone);
if (m_pad_config.padsquircling != 0) if (profile->padsquircling != 0)
{ {
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
} }
pad->m_sticks[0].m_value = lx; pad->m_sticks[0].m_value = lx;
@ -415,26 +425,27 @@ void mm_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16&
{ {
// Update the pad button values based on their type and thresholds. // Update the pad button values based on their type and thresholds.
// With this you can use axis or triggers as buttons or vice versa // With this you can use axis or triggers as buttons or vice versa
auto p_profile = m_dev->config;
if (keyCode == m_dev->trigger_left) if (keyCode == m_dev->trigger_left)
{ {
pressed = val > (ignore_threshold ? 0 : m_pad_config.ltriggerthreshold); pressed = val > (ignore_threshold ? 0 : p_profile->ltriggerthreshold);
val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0; val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0;
} }
else if (keyCode == m_dev->trigger_right) else if (keyCode == m_dev->trigger_right)
{ {
pressed = val > (ignore_threshold ? 0 : m_pad_config.rtriggerthreshold); pressed = val > (ignore_threshold ? 0 : p_profile->rtriggerthreshold);
val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0; val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0;
} }
else if (std::find(m_dev->axis_left.begin(), m_dev->axis_left.end(), keyCode) != m_dev->axis_left.end()) else if (std::find(m_dev->axis_left.begin(), m_dev->axis_left.end(), keyCode) != m_dev->axis_left.end())
{ {
pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0; val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0;
} }
else if (std::find(m_dev->axis_right.begin(), m_dev->axis_right.end(), keyCode) != m_dev->axis_right.end()) else if (std::find(m_dev->axis_right.begin(), m_dev->axis_right.end(), keyCode) != m_dev->axis_right.end())
{ {
pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0; val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0;
} }
else // normal button (should in theory also support sensitive buttons) else // normal button (should in theory also support sensitive buttons)
{ {
@ -486,9 +497,9 @@ std::unordered_map<u64, u16> mm_joystick_handler::GetButtonValues(const JOYINFOE
} }
else if (js_caps.wCaps & JOYCAPS_POV4DIR) else if (js_caps.wCaps & JOYCAPS_POV4DIR)
{ {
u64 val = js_info.dwPOV; int val = static_cast<int>(js_info.dwPOV);
auto emplacePOV = [&button_values, &val](u64 pov) auto emplacePOV = [&button_values, &val](int pov)
{ {
int cw = pov + 4500, ccw = pov - 4500; int cw = pov + 4500, ccw = pov - 4500;
bool pressed = (val == pov) || (val == cw) || (ccw < 0 ? val == 36000 - std::abs(ccw) : val == ccw); bool pressed = (val == pov) || (val == cw) || (ccw < 0 ? val == 36000 - std::abs(ccw) : val == ccw);
@ -540,9 +551,7 @@ int mm_joystick_handler::GetIDByName(const std::string& name)
for (auto dev : m_devices) for (auto dev : m_devices)
{ {
if (dev.second.device_name == name) if (dev.second.device_name == name)
{
return dev.first; return dev.first;
}
} }
return -1; return -1;
} }

View File

@ -90,6 +90,7 @@ class mm_joystick_handler final : public PadHandlerBase
{ {
u32 device_id{ 0 }; u32 device_id{ 0 };
std::string device_name{ "" }; std::string device_name{ "" };
pad_config* config{ nullptr };
JOYINFOEX device_info; JOYINFOEX device_info;
JOYCAPS device_caps; JOYCAPS device_caps;
u64 trigger_left = 0; u64 trigger_left = 0;
@ -108,6 +109,7 @@ public:
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override; void ThreadProc() override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void init_config(pad_config* cfg, const std::string& name) override;
private: private:
void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override;
@ -116,7 +118,7 @@ private:
bool GetMMJOYDevice(int index, MMJOYDevice& dev); bool GetMMJOYDevice(int index, MMJOYDevice& dev);
bool is_init = false; bool is_init = false;
u32 supportedJoysticks = 0; u32 m_supported_joysticks = 0;
std::vector<u64> blacklist; std::vector<u64> blacklist;
std::unordered_map<int, MMJOYDevice> m_devices; std::unordered_map<int, MMJOYDevice> m_devices;

View File

@ -30,7 +30,7 @@ void pad_thread::Init(const u32 max_connect)
m_info.max_connect = std::min(max_connect, (u32)7); // max 7 pads m_info.max_connect = std::min(max_connect, (u32)7); // max 7 pads
m_info.now_connect = 0; m_info.now_connect = 0;
input_cfg.load(); g_cfg_input.load();
std::shared_ptr<keyboard_pad_handler> keyptr; std::shared_ptr<keyboard_pad_handler> keyptr;
@ -42,7 +42,7 @@ void pad_thread::Init(const u32 max_connect)
{ {
std::shared_ptr<PadHandlerBase> cur_pad_handler; std::shared_ptr<PadHandlerBase> cur_pad_handler;
const auto &handler_type = input_cfg.player_input[i]; const auto &handler_type = g_cfg_input.player[i]->handler;
if (handlers.count(handler_type) != 0) if (handlers.count(handler_type) != 0)
{ {
@ -87,11 +87,11 @@ void pad_thread::Init(const u32 max_connect)
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR,
CELL_PAD_DEV_TYPE_STANDARD)); CELL_PAD_DEV_TYPE_STANDARD));
if (cur_pad_handler->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->to_string()) == false) if (cur_pad_handler->bindPadToDevice(m_pads.back(), g_cfg_input.player[i]->device.to_string()) == false)
{ {
//Failed to bind the device to cur_pad_handler so binds to NullPadHandler //Failed to bind the device to cur_pad_handler so binds to NullPadHandler
LOG_ERROR(GENERAL, "Failed to bind device %s to handler %s", input_cfg.player_device[i]->to_string(), handler_type.to_string()); LOG_ERROR(GENERAL, "Failed to bind device %s to handler %s", g_cfg_input.player[i]->device.to_string(), handler_type.to_string());
nullpad->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->to_string()); nullpad->bindPadToDevice(m_pads.back(), g_cfg_input.player[i]->device.to_string());
} }
} }

View File

@ -3,7 +3,6 @@
#include <map> #include <map>
#include <thread> #include <thread>
#include "Emu/System.h"
#include "../Utilities/types.h" #include "../Utilities/types.h"
#include "Emu/Io/PadHandler.h" #include "Emu/Io/PadHandler.h"

View File

@ -10,16 +10,42 @@
#endif #endif
#include "../keyboard_pad_handler.h" #include "../keyboard_pad_handler.h"
#include "../Emu/Io/Null/NullPadHandler.h" #include "../Emu/Io/Null/NullPadHandler.h"
#include "../Emu/System.h"
#include <QJsonObject> #include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QInputDialog>
input_config input_cfg; #include <QMessageBox>
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString; constexpr auto qstr = QString::fromStdString;
inline bool CreateConfigFile(const QString& dir, const QString& name)
{
QString input_dir = qstr(fs::get_config_dir()) + "/InputConfigs/";
if (!QDir().mkdir(input_dir) && !QDir().exists(input_dir))
{
LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(input_dir));
return false;
}
if (!QDir().mkdir(dir) && !QDir().exists(dir))
{
LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(dir));
return false;
}
QString filename = dir + name + ".yml";
QFile new_file(filename);
if (!new_file.open(QIODevice::WriteOnly))
{
LOG_ERROR(GENERAL, "Failed to create file %s", sstr(filename));
return false;
}
new_file.close();
return true;
};
// taken from https://stackoverflow.com/a/30818424/8353754 // taken from https://stackoverflow.com/a/30818424/8353754
// because size policies won't work as expected (see similar bugs in Qt bugtracker) // because size policies won't work as expected (see similar bugs in Qt bugtracker)
inline void resizeComboBoxView(QComboBox* combo) inline void resizeComboBoxView(QComboBox* combo)
@ -55,8 +81,8 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
QVBoxLayout *dialog_layout = new QVBoxLayout(); QVBoxLayout *dialog_layout = new QVBoxLayout();
QHBoxLayout *all_players = new QHBoxLayout(); QHBoxLayout *all_players = new QHBoxLayout();
input_cfg.from_default(); g_cfg_input.from_default();
input_cfg.load(); g_cfg_input.load();
for (int i = 0; i < MAX_PLAYERS; i++) for (int i = 0; i < MAX_PLAYERS; i++)
{ {
@ -80,20 +106,27 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
co_deviceID[i]->view()->setTextElideMode(Qt::ElideNone); co_deviceID[i]->view()->setTextElideMode(Qt::ElideNone);
ppad_layout->addWidget(co_deviceID[i]); ppad_layout->addWidget(co_deviceID[i]);
co_profile[i] = new QComboBox();
co_profile[i]->setEnabled(false);
co_profile[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
co_profile[i]->view()->setTextElideMode(Qt::ElideNone);
ppad_layout->addWidget(co_profile[i]);
QHBoxLayout *button_layout = new QHBoxLayout(); QHBoxLayout *button_layout = new QHBoxLayout();
bu_config[i] = new QPushButton(tr("Config")); bu_new_profile[i] = new QPushButton(tr("Add Profile"));
bu_new_profile[i]->setEnabled(false);
bu_config[i] = new QPushButton(tr("Configure"));
bu_config[i]->setEnabled(false); bu_config[i]->setEnabled(false);
bu_config[i]->setFixedSize(bu_config[i]->sizeHint()); button_layout->setContentsMargins(0,0,0,0);
button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f);
button_layout->addWidget(bu_config[i]); button_layout->addWidget(bu_config[i]);
button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f); button_layout->addWidget(bu_new_profile[i]);
ppad_layout->addLayout(button_layout); ppad_layout->addLayout(button_layout);
grp_player->setLayout(ppad_layout); grp_player->setLayout(ppad_layout);
grp_player->setFixedSize(grp_player->sizeHint()); grp_player->setFixedSize(grp_player->sizeHint());
// fill comboboxes after setting the groupbox's size to prevent stretch // fill comboboxes after setting the groupbox's size to prevent stretch
std::vector<std::string> str_inputs = input_cfg.player_input[0].to_list(); std::vector<std::string> str_inputs = g_cfg_input.player[0]->handler.to_list();
for (int index = 0; index < str_inputs.size(); index++) for (int index = 0; index < str_inputs.size(); index++)
{ {
co_inputtype[i]->addItem(qstr(str_inputs[index])); co_inputtype[i]->addItem(qstr(str_inputs[index]));
@ -132,7 +165,7 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
for (int i = 0; i < MAX_PLAYERS; i++) for (int i = 0; i < MAX_PLAYERS; i++)
{ {
// No extra loops are necessary because setCurrentText does it for us // No extra loops are necessary because setCurrentText does it for us
co_inputtype[i]->setCurrentText(qstr(input_cfg.player_input[i].to_string())); co_inputtype[i]->setCurrentText(qstr(g_cfg_input.player[i]->handler.to_string()));
// Device will be empty on some rare occasions, so fill them by force // Device will be empty on some rare occasions, so fill them by force
ChangeInputType(i); ChangeInputType(i);
} }
@ -140,18 +173,67 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
for (int i = 0; i < MAX_PLAYERS; i++) for (int i = 0; i < MAX_PLAYERS; i++)
{ {
connect(co_inputtype[i], &QComboBox::currentTextChanged, [=] { ChangeInputType(i); }); connect(co_inputtype[i], &QComboBox::currentTextChanged, [=]
{
ChangeInputType(i);
});
connect(co_deviceID[i], &QComboBox::currentTextChanged, [=](const QString& dev) connect(co_deviceID[i], &QComboBox::currentTextChanged, [=](const QString& dev)
{ {
std::string device = sstr(dev); std::string device = sstr(dev);
if (!input_cfg.player_device[i]->from_string(device)) if (!g_cfg_input.player[i]->device.from_string(device))
{ {
//Something went wrong //Something went wrong
LOG_ERROR(GENERAL, "Failed to convert device string: %s", device); LOG_ERROR(GENERAL, "Failed to convert device string: %s", device);
return; return;
} }
}); });
connect(bu_config[i], &QAbstractButton::clicked, [=] { ClickConfigButton(i); }); connect(co_profile[i], &QComboBox::currentTextChanged, [=](const QString& prof)
{
std::string profile = sstr(prof);
if (!g_cfg_input.player[i]->profile.from_string(profile))
{
//Something went wrong
LOG_ERROR(GENERAL, "Failed to convert profile string: %s", profile);
return;
}
});
connect(bu_config[i], &QAbstractButton::clicked, [=]
{
ClickConfigButton(i);
});
connect(bu_new_profile[i], &QAbstractButton::clicked, [=]
{
QInputDialog* dialog = new QInputDialog(this);
dialog->setWindowTitle(tr("Choose a unique name"));
dialog->setLabelText(tr("Profile Name: "));
dialog->setFixedSize(500, 100);
while (dialog->exec() != QDialog::Rejected)
{
QString friendlyName = dialog->textValue();
if (friendlyName == "")
{
QMessageBox::warning(this, tr("Error"), tr("Name cannot be empty"));
continue;
}
if (friendlyName.contains("."))
{
QMessageBox::warning(this, tr("Error"), tr("Must choose a name without '.'"));
continue;
}
if (co_profile[i]->findText(friendlyName) != -1)
{
QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name"));
continue;
}
if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(g_cfg_input.player[i]->handler)), friendlyName))
{
co_profile[i]->addItem(friendlyName);
co_profile[i]->setCurrentText(friendlyName);
}
break;
}
});
} }
connect(ok_button, &QPushButton::pressed, this, &gamepads_settings_dialog::SaveExit); connect(ok_button, &QPushButton::pressed, this, &gamepads_settings_dialog::SaveExit);
connect(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit); connect(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit);
@ -167,12 +249,13 @@ void gamepads_settings_dialog::SaveExit()
{ {
if (co_deviceID[i]->currentData() == -1) if (co_deviceID[i]->currentData() == -1)
{ {
input_cfg.player_input[i].from_default(); g_cfg_input.player[i]->handler.from_default();
input_cfg.player_device[i]->from_default(); g_cfg_input.player[i]->device.from_default();
g_cfg_input.player[i]->profile.from_default();
} }
} }
input_cfg.save(); g_cfg_input.save();
QDialog::accept(); QDialog::accept();
} }
@ -180,8 +263,8 @@ void gamepads_settings_dialog::SaveExit()
void gamepads_settings_dialog::CancelExit() void gamepads_settings_dialog::CancelExit()
{ {
//Reloads config from file or defaults //Reloads config from file or defaults
input_cfg.from_default(); g_cfg_input.from_default();
input_cfg.load(); g_cfg_input.load();
QDialog::accept(); QDialog::accept();
} }
@ -224,10 +307,11 @@ std::shared_ptr<PadHandlerBase> gamepads_settings_dialog::GetHandler(pad_handler
void gamepads_settings_dialog::ChangeInputType(int player) void gamepads_settings_dialog::ChangeInputType(int player)
{ {
std::string handler = sstr(co_inputtype[player]->currentText()); std::string handler = sstr(co_inputtype[player]->currentText());
std::string device = input_cfg.player_device[player]->to_string(); std::string device = g_cfg_input.player[player]->device.to_string();
std::string profile = g_cfg_input.player[player]->profile.to_string();
// Change this player's current handler // Change this player's current handler
if (!input_cfg.player_input[player].from_string(handler)) if (!g_cfg_input.player[player]->handler.from_string(handler))
{ {
//Something went wrong //Something went wrong
LOG_ERROR(GENERAL, "Failed to convert input string:%s", handler); LOG_ERROR(GENERAL, "Failed to convert input string:%s", handler);
@ -235,7 +319,7 @@ void gamepads_settings_dialog::ChangeInputType(int player)
} }
// Get this player's current handler and it's currently available devices // Get this player's current handler and it's currently available devices
std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(input_cfg.player_input[player]); std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(g_cfg_input.player[player]->handler);
std::vector<std::string> list_devices = cur_pad_handler->ListDevices(); std::vector<std::string> list_devices = cur_pad_handler->ListDevices();
// Refill the device combobox with currently available devices // Refill the device combobox with currently available devices
@ -258,19 +342,60 @@ void gamepads_settings_dialog::ChangeInputType(int player)
co_deviceID[player]->addItem(tr("No Device Detected"), -1); co_deviceID[player]->addItem(tr("No Device Detected"), -1);
} }
// Update view and enable configuration if possible bool config_enabled = device_found && cur_pad_handler->has_config();
co_profile[player]->clear();
// update profile list if possible
if (config_enabled)
{
QString s_profile_dir = qstr(PadHandlerBase::get_config_dir(cur_pad_handler->m_type));
QStringList profiles = gui_settings::GetDirEntries(QDir(s_profile_dir), QStringList() << "*.yml");
if (profiles.isEmpty())
{
QString def_name = "Default Profile";
if (!CreateConfigFile(s_profile_dir, def_name))
{
config_enabled = false;
}
else
{
co_profile[player]->addItem(def_name);
co_profile[player]->setCurrentText(def_name);
}
}
else
{
for (const auto& prof : profiles)
{
co_profile[player]->addItem(prof);
}
co_profile[player]->setCurrentText(qstr(profile));
}
}
if (!config_enabled)
co_profile[player]->addItem(tr("No Profiles"));
// enable configuration and profile list if possible
bu_config[player]->setEnabled(config_enabled);
bu_new_profile[player]->setEnabled(config_enabled);
co_profile[player]->setEnabled(config_enabled);
// update view
resizeComboBoxView(co_deviceID[player]); resizeComboBoxView(co_deviceID[player]);
bu_config[player]->setEnabled(device_found && cur_pad_handler->has_config()); resizeComboBoxView(co_profile[player]);
} }
void gamepads_settings_dialog::ClickConfigButton(int player) void gamepads_settings_dialog::ClickConfigButton(int player)
{ {
// Get this player's current handler and open its pad settings dialog // Get this player's current handler and open its pad settings dialog
std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(input_cfg.player_input[player]); std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(g_cfg_input.player[player]->handler);
if (cur_pad_handler->has_config()) if (cur_pad_handler->has_config())
{ {
std::string device = sstr(co_deviceID[player]->currentText()); std::string device = sstr(co_deviceID[player]->currentText());
pad_settings_dialog dlg(device, cur_pad_handler); std::string profile = sstr(co_profile[player]->currentText());
pad_settings_dialog dlg(device, profile, cur_pad_handler);
dlg.exec(); dlg.exec();
} }
} }

View File

@ -12,52 +12,6 @@
#include "../../Utilities/File.h" #include "../../Utilities/File.h"
#include "../Emu/Io/PadHandler.h" #include "../Emu/Io/PadHandler.h"
struct input_config final : cfg::node
{
const std::string cfg_name = fs::get_config_dir() + "/config_input.yml";
cfg::_enum<pad_handler> player_input[7]{
{ this, "Player 1 Input", pad_handler::keyboard },
{ this, "Player 2 Input", pad_handler::null },
{ this, "Player 3 Input", pad_handler::null },
{ this, "Player 4 Input", pad_handler::null },
{ this, "Player 5 Input", pad_handler::null },
{ this, "Player 6 Input", pad_handler::null },
{ this, "Player 7 Input", pad_handler::null } };
cfg::string player1{ this, "Player 1 Device", "Keyboard" };
cfg::string player2{ this, "Player 2 Device", "Default Null Device" };
cfg::string player3{ this, "Player 3 Device", "Default Null Device" };
cfg::string player4{ this, "Player 4 Device", "Default Null Device" };
cfg::string player5{ this, "Player 5 Device", "Default Null Device" };
cfg::string player6{ this, "Player 6 Device", "Default Null Device" };
cfg::string player7{ this, "Player 7 Device", "Default Null Device" };
cfg::string *player_device[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);
}
};
extern input_config input_cfg;
class gamepads_settings_dialog : public QDialog class gamepads_settings_dialog : public QDialog
{ {
const int MAX_PLAYERS = 7; const int MAX_PLAYERS = 7;
@ -72,7 +26,9 @@ protected:
protected: protected:
QComboBox *co_inputtype[7]; QComboBox *co_inputtype[7];
QComboBox *co_deviceID[7]; QComboBox *co_deviceID[7];
QComboBox *co_profile[7];
QPushButton *bu_config[7]; QPushButton *bu_config[7];
QPushButton *bu_new_profile[7];
public: public:
gamepads_settings_dialog(QWidget* parent); gamepads_settings_dialog(QWidget* parent);

View File

@ -321,6 +321,17 @@ QStringList gui_settings::GetConfigEntries()
return res; return res;
} }
QStringList gui_settings::GetDirEntries(const QDir& dir, const QStringList& nameFilters)
{
QFileInfoList entries = dir.entryInfoList(nameFilters, QDir::Files);
QStringList res;
for (const QFileInfo &entry : entries)
{
res.append(entry.baseName());
}
return res;
}
void gui_settings::BackupSettingsToTarget(const QString& friendlyName) void gui_settings::BackupSettingsToTarget(const QString& friendlyName)
{ {
QSettings target(ComputeSettingsDir() + friendlyName + ".ini", QSettings::Format::IniFormat); QSettings target(ComputeSettingsDir() + friendlyName + ".ini", QSettings::Format::IniFormat);

View File

@ -231,6 +231,7 @@ public:
bool GetGamelistColVisibility(int col); bool GetGamelistColVisibility(int col);
QColor GetCustomColor(int col); QColor GetCustomColor(int col);
QStringList GetConfigEntries(); QStringList GetConfigEntries();
static QStringList GetDirEntries(const QDir& dir, const QStringList& nameFilters);
QString GetCurrentStylesheetPath(); QString GetCurrentStylesheetPath();
QStringList GetStylesheetEntries(); QStringList GetStylesheetEntries();
QStringList GetGameListCategoryFilters(); QStringList GetGameListCategoryFilters();

View File

@ -13,11 +13,9 @@
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString; constexpr auto qstr = QString::fromStdString;
pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ptr<PadHandlerBase> handler, QWidget *parent) pad_settings_dialog::pad_settings_dialog(const std::string& device, const std::string& profile, std::shared_ptr<PadHandlerBase> handler, QWidget *parent)
: QDialog(parent), ui(new Ui::pad_settings_dialog), m_handler_cfg(handler->GetConfig()), m_device_name(device), m_handler(handler) : QDialog(parent), ui(new Ui::pad_settings_dialog), m_device_name(device), m_handler(handler), m_handler_type(handler->m_type)
{ {
m_handler_cfg->load();
ui->setupUi(this); ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@ -28,37 +26,47 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_
m_padButtons = new QButtonGroup(this); m_padButtons = new QButtonGroup(this);
m_palette = ui->b_left->palette(); // save normal palette m_palette = ui->b_left->palette(); // save normal palette
ui->chb_vibration_large->setChecked((bool)m_handler_cfg->enable_vibration_motor_large); std::string cfg_name = PadHandlerBase::get_config_dir(m_handler_type) + profile + ".yml";
ui->chb_vibration_small->setChecked((bool)m_handler_cfg->enable_vibration_motor_small);
ui->chb_vibration_switch->setChecked((bool)m_handler_cfg->switch_vibration_motors);
// Adjust to the different pad handlers // Adjust to the different pad handlers
if (m_handler_cfg->cfg_type == "keyboard") if (m_handler_type == pad_handler::keyboard)
{ {
setWindowTitle(tr("Configure Keyboard")); setWindowTitle(tr("Configure Keyboard"));
m_handler_type = handler_type::handler_type_keyboard;
ui->b_blacklist->setEnabled(false); ui->b_blacklist->setEnabled(false);
((keyboard_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name);
} }
else if (m_handler_cfg->cfg_type == "xinput") else if (m_handler_type == pad_handler::ds4)
{
setWindowTitle(tr("Configure XInput"));
m_handler_type = handler_type::handler_type_xinput;
}
else if (m_handler_cfg->cfg_type == "ds4")
{ {
setWindowTitle(tr("Configure DS4")); setWindowTitle(tr("Configure DS4"));
m_handler_type = handler_type::handler_type_ds4; ((ds4_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name);
} }
else if (m_handler_cfg->cfg_type == "mmjoystick") #ifdef _MSC_VER
else if (m_handler_type == pad_handler::xinput)
{
setWindowTitle(tr("Configure XInput"));
((xinput_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name);
}
#endif
#ifdef _WIN32
else if (m_handler_type == pad_handler::mm)
{ {
setWindowTitle(tr("Configure MMJoystick")); setWindowTitle(tr("Configure MMJoystick"));
m_handler_type = handler_type::handler_type_mmjoy; ((mm_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name);
} }
else if (m_handler_cfg->cfg_type == "evdev") #endif
#ifdef HAVE_LIBEVDEV
else if (m_handler_type == pad_handler::evdev)
{ {
setWindowTitle(tr("Configure evdev")); setWindowTitle(tr("Configure evdev"));
m_handler_type = handler_type::handler_type_evdev; ((evdev_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name);
} }
#endif
m_handler_cfg.load();
ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large);
ui->chb_vibration_small->setChecked((bool)m_handler_cfg.enable_vibration_motor_small);
ui->chb_vibration_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors);
// Enable Button Remapping // Enable Button Remapping
if (m_handler->has_config()) if (m_handler->has_config())
@ -85,7 +93,7 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_
if (val <= 0) return; if (val <= 0) return;
LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler_cfg->cfg_type, name, val); LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler_type, name, val);
if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end) if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end)
{ {
m_cfg_entries[m_button_id].key = name; m_cfg_entries[m_button_id].key = name;
@ -185,14 +193,14 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_
}; };
// Enable Trigger Thresholds // Enable Trigger Thresholds
initSlider(ui->slider_trigger_left, m_handler_cfg->ltriggerthreshold, 0, m_handler->trigger_max); initSlider(ui->slider_trigger_left, m_handler_cfg.ltriggerthreshold, 0, m_handler->trigger_max);
initSlider(ui->slider_trigger_right, m_handler_cfg->rtriggerthreshold, 0, m_handler->trigger_max); initSlider(ui->slider_trigger_right, m_handler_cfg.rtriggerthreshold, 0, m_handler->trigger_max);
ui->preview_trigger_left->setRange(0, m_handler->trigger_max); ui->preview_trigger_left->setRange(0, m_handler->trigger_max);
ui->preview_trigger_right->setRange(0, m_handler->trigger_max); ui->preview_trigger_right->setRange(0, m_handler->trigger_max);
// Enable Stick Deadzones // Enable Stick Deadzones
initSlider(ui->slider_stick_left, m_handler_cfg->lstickdeadzone, 0, m_handler->thumb_max); initSlider(ui->slider_stick_left, m_handler_cfg.lstickdeadzone, 0, m_handler->thumb_max);
initSlider(ui->slider_stick_right, m_handler_cfg->rstickdeadzone, 0, m_handler->thumb_max); initSlider(ui->slider_stick_right, m_handler_cfg.rstickdeadzone, 0, m_handler->thumb_max);
RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->sizeHint().width(), lx, ly); RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->sizeHint().width(), lx, ly);
connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value) connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value)
@ -224,37 +232,37 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_
button->installEventFilter(this); button->installEventFilter(this);
}; };
insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg->ls_left); insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg.ls_left);
insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg->ls_down); insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg.ls_down);
insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg->ls_right); insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg.ls_right);
insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg->ls_up); insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg.ls_up);
insertButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg->left); insertButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg.left);
insertButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg->down); insertButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg.down);
insertButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg->right); insertButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg.right);
insertButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg->up); insertButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg.up);
insertButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg->l1); insertButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg.l1);
insertButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg->l2); insertButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg.l2);
insertButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg->l3); insertButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg.l3);
insertButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg->start); insertButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg.start);
insertButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg->select); insertButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg.select);
insertButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg->ps); insertButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg.ps);
insertButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg->r1); insertButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg.r1);
insertButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg->r2); insertButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg.r2);
insertButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg->r3); insertButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg.r3);
insertButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg->square); insertButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg.square);
insertButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg->cross); insertButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg.cross);
insertButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg->circle); insertButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg.circle);
insertButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg->triangle); insertButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg.triangle);
insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg->rs_left); insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg.rs_left);
insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg->rs_down); insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg.rs_down);
insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg->rs_right); insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right);
insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg->rs_up); insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up);
m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters); m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters);
m_padButtons->addButton(ui->b_blacklist, button_ids::id_blacklist); m_padButtons->addButton(ui->b_blacklist, button_ids::id_blacklist);
@ -345,7 +353,7 @@ void pad_settings_dialog::RepaintPreviewLabel(QLabel* l, int dz, int w, int x, i
void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent)
{ {
if (m_handler_type != handler_type::handler_type_keyboard) if (m_handler_type != pad_handler::keyboard)
{ {
return; return;
} }
@ -370,7 +378,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent)
void pad_settings_dialog::mousePressEvent(QMouseEvent* event) void pad_settings_dialog::mousePressEvent(QMouseEvent* event)
{ {
if (m_handler_type != handler_type::handler_type_keyboard) if (m_handler_type != pad_handler::keyboard)
{ {
return; return;
} }
@ -407,17 +415,17 @@ void pad_settings_dialog::UpdateLabel(bool is_reset)
{ {
if (m_handler->has_rumble()) if (m_handler->has_rumble())
{ {
ui->chb_vibration_large->setChecked((bool)m_handler_cfg->enable_vibration_motor_large); ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large);
ui->chb_vibration_small->setChecked((bool)m_handler_cfg->enable_vibration_motor_small); ui->chb_vibration_small->setChecked((bool)m_handler_cfg.enable_vibration_motor_small);
ui->chb_vibration_switch->setChecked((bool)m_handler_cfg->switch_vibration_motors); ui->chb_vibration_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors);
} }
if (m_handler->has_deadzones()) if (m_handler->has_deadzones())
{ {
ui->slider_trigger_left->setValue(m_handler_cfg->ltriggerthreshold); ui->slider_trigger_left->setValue(m_handler_cfg.ltriggerthreshold);
ui->slider_trigger_right->setValue(m_handler_cfg->rtriggerthreshold); ui->slider_trigger_right->setValue(m_handler_cfg.rtriggerthreshold);
ui->slider_stick_left->setValue(m_handler_cfg->lstickdeadzone); ui->slider_stick_left->setValue(m_handler_cfg.lstickdeadzone);
ui->slider_stick_right->setValue(m_handler_cfg->rstickdeadzone); ui->slider_stick_right->setValue(m_handler_cfg.rstickdeadzone);
} }
} }
@ -450,20 +458,20 @@ void pad_settings_dialog::SaveConfig()
if (m_handler->has_rumble()) if (m_handler->has_rumble())
{ {
m_handler_cfg->enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked()); m_handler_cfg.enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked());
m_handler_cfg->enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked()); m_handler_cfg.enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked());
m_handler_cfg->switch_vibration_motors.set(ui->chb_vibration_switch->isChecked()); m_handler_cfg.switch_vibration_motors.set(ui->chb_vibration_switch->isChecked());
} }
if (m_handler->has_deadzones()) if (m_handler->has_deadzones())
{ {
m_handler_cfg->ltriggerthreshold.set(ui->slider_trigger_left->value()); m_handler_cfg.ltriggerthreshold.set(ui->slider_trigger_left->value());
m_handler_cfg->rtriggerthreshold.set(ui->slider_trigger_right->value()); m_handler_cfg.rtriggerthreshold.set(ui->slider_trigger_right->value());
m_handler_cfg->lstickdeadzone.set(ui->slider_stick_left->value()); m_handler_cfg.lstickdeadzone.set(ui->slider_stick_left->value());
m_handler_cfg->rstickdeadzone.set(ui->slider_stick_right->value()); m_handler_cfg.rstickdeadzone.set(ui->slider_stick_right->value());
} }
m_handler_cfg->save(); m_handler_cfg.save();
} }
void pad_settings_dialog::OnPadButtonClicked(int id) void pad_settings_dialog::OnPadButtonClicked(int id)
@ -476,7 +484,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
return; return;
case button_ids::id_reset_parameters: case button_ids::id_reset_parameters:
ReactivateButtons(); ReactivateButtons();
m_handler_cfg->from_default(); m_handler_cfg.from_default();
UpdateLabel(true); UpdateLabel(true);
return; return;
case button_ids::id_blacklist: case button_ids::id_blacklist:

View File

@ -17,6 +17,12 @@
#ifdef _WIN32 #ifdef _WIN32
#include "xinput_pad_handler.h" #include "xinput_pad_handler.h"
#endif #endif
#ifdef _MSC_VER
#include "mm_joystick_handler.h"
#endif
#ifdef HAVE_LIBEVDEV
#include "evdev_joystick_handler.h"
#endif
#include "ds4_pad_handler.h" #include "ds4_pad_handler.h"
namespace Ui namespace Ui
@ -72,15 +78,6 @@ class pad_settings_dialog : public QDialog
id_cancel id_cancel
}; };
enum handler_type
{
handler_type_keyboard,
handler_type_xinput,
handler_type_ds4,
handler_type_mmjoy,
handler_type_evdev
};
struct pad_button struct pad_button
{ {
cfg::string* cfg_name; cfg::string* cfg_name;
@ -109,9 +106,9 @@ private:
QPalette m_palette; QPalette m_palette;
// Pad Handlers // Pad Handlers
pad_handler m_handler_type;
std::shared_ptr<PadHandlerBase> m_handler; std::shared_ptr<PadHandlerBase> m_handler;
handler_type m_handler_type; pad_config m_handler_cfg;
pad_config* m_handler_cfg;
std::string m_device_name; std::string m_device_name;
// Remap Timer // Remap Timer
@ -129,7 +126,7 @@ private:
void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y); void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y);
public: public:
explicit pad_settings_dialog(const std::string& device, std::shared_ptr<PadHandlerBase> handler, QWidget *parent = nullptr); explicit pad_settings_dialog(const std::string& device, const std::string& profile, std::shared_ptr<PadHandlerBase> handler, QWidget *parent = nullptr);
~pad_settings_dialog(); ~pad_settings_dialog();
/** Handle keyboard handler input */ /** Handle keyboard handler input */

View File

@ -1,12 +1,11 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#include "xinput_pad_handler.h" #include "xinput_pad_handler.h"
#include "rpcs3qt/pad_settings_dialog.h"
xinput_pad_handler::xinput_pad_handler() : xinput_pad_handler::xinput_pad_handler() : PadHandlerBase(pad_handler::xinput)
library(nullptr), xinputGetState(nullptr), xinputEnable(nullptr),
xinputSetState(nullptr), xinputGetBatteryInformation(nullptr), is_init(false)
{ {
init_configs();
// Define border values // Define border values
thumb_min = -32768; thumb_min = -32768;
thumb_max = 32767; thumb_max = 32767;
@ -15,47 +14,6 @@ xinput_pad_handler::xinput_pad_handler() :
vibration_min = 0; vibration_min = 0;
vibration_max = 65535; vibration_max = 65535;
// Set this handler's type and save location
m_pad_config.cfg_type = "xinput";
m_pad_config.cfg_name = fs::get_config_dir() + "/config_xinput.yml";
// Set default button mapping
m_pad_config.ls_left.def = button_list.at(XInputKeyCodes::LSXNeg);
m_pad_config.ls_down.def = button_list.at(XInputKeyCodes::LSYNeg);
m_pad_config.ls_right.def = button_list.at(XInputKeyCodes::LSXPos);
m_pad_config.ls_up.def = button_list.at(XInputKeyCodes::LSYPos);
m_pad_config.rs_left.def = button_list.at(XInputKeyCodes::RSXNeg);
m_pad_config.rs_down.def = button_list.at(XInputKeyCodes::RSYNeg);
m_pad_config.rs_right.def = button_list.at(XInputKeyCodes::RSXPos);
m_pad_config.rs_up.def = button_list.at(XInputKeyCodes::RSYPos);
m_pad_config.start.def = button_list.at(XInputKeyCodes::Start);
m_pad_config.select.def = button_list.at(XInputKeyCodes::Back);
m_pad_config.ps.def = button_list.at(XInputKeyCodes::Guide);
m_pad_config.square.def = button_list.at(XInputKeyCodes::X);
m_pad_config.cross.def = button_list.at(XInputKeyCodes::A);
m_pad_config.circle.def = button_list.at(XInputKeyCodes::B);
m_pad_config.triangle.def = button_list.at(XInputKeyCodes::Y);
m_pad_config.left.def = button_list.at(XInputKeyCodes::Left);
m_pad_config.down.def = button_list.at(XInputKeyCodes::Down);
m_pad_config.right.def = button_list.at(XInputKeyCodes::Right);
m_pad_config.up.def = button_list.at(XInputKeyCodes::Up);
m_pad_config.r1.def = button_list.at(XInputKeyCodes::RB);
m_pad_config.r2.def = button_list.at(XInputKeyCodes::RT);
m_pad_config.r3.def = button_list.at(XInputKeyCodes::RS);
m_pad_config.l1.def = button_list.at(XInputKeyCodes::LB);
m_pad_config.l2.def = button_list.at(XInputKeyCodes::LT);
m_pad_config.l3.def = button_list.at(XInputKeyCodes::LS);
// Set default misc variables
m_pad_config.lstickdeadzone.def = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; // between 0 and 32767
m_pad_config.rstickdeadzone.def = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; // between 0 and 32767
m_pad_config.ltriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255
m_pad_config.rtriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255
m_pad_config.padsquircling.def = 8000;
// apply defaults
m_pad_config.from_default();
// set capabilities // set capabilities
b_has_config = true; b_has_config = true;
b_has_rumble = true; b_has_rumble = true;
@ -70,6 +28,49 @@ xinput_pad_handler::~xinput_pad_handler()
Close(); Close();
} }
void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name)
{
// Set this profile's save location
cfg->cfg_name = name;
// Set default button mapping
cfg->ls_left.def = button_list.at(XInputKeyCodes::LSXNeg);
cfg->ls_down.def = button_list.at(XInputKeyCodes::LSYNeg);
cfg->ls_right.def = button_list.at(XInputKeyCodes::LSXPos);
cfg->ls_up.def = button_list.at(XInputKeyCodes::LSYPos);
cfg->rs_left.def = button_list.at(XInputKeyCodes::RSXNeg);
cfg->rs_down.def = button_list.at(XInputKeyCodes::RSYNeg);
cfg->rs_right.def = button_list.at(XInputKeyCodes::RSXPos);
cfg->rs_up.def = button_list.at(XInputKeyCodes::RSYPos);
cfg->start.def = button_list.at(XInputKeyCodes::Start);
cfg->select.def = button_list.at(XInputKeyCodes::Back);
cfg->ps.def = button_list.at(XInputKeyCodes::Guide);
cfg->square.def = button_list.at(XInputKeyCodes::X);
cfg->cross.def = button_list.at(XInputKeyCodes::A);
cfg->circle.def = button_list.at(XInputKeyCodes::B);
cfg->triangle.def = button_list.at(XInputKeyCodes::Y);
cfg->left.def = button_list.at(XInputKeyCodes::Left);
cfg->down.def = button_list.at(XInputKeyCodes::Down);
cfg->right.def = button_list.at(XInputKeyCodes::Right);
cfg->up.def = button_list.at(XInputKeyCodes::Up);
cfg->r1.def = button_list.at(XInputKeyCodes::RB);
cfg->r2.def = button_list.at(XInputKeyCodes::RT);
cfg->r3.def = button_list.at(XInputKeyCodes::RS);
cfg->l1.def = button_list.at(XInputKeyCodes::LB);
cfg->l2.def = button_list.at(XInputKeyCodes::LT);
cfg->l3.def = button_list.at(XInputKeyCodes::LS);
// Set default misc variables
cfg->lstickdeadzone.def = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; // between 0 and 32767
cfg->rstickdeadzone.def = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; // between 0 and 32767
cfg->ltriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255
cfg->rtriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255
cfg->padsquircling.def = 8000;
// apply defaults
cfg->from_default();
}
void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons) void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons)
{ {
if (get_blacklist) if (get_blacklist)
@ -152,29 +153,30 @@ void xinput_pad_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& v
{ {
// Update the pad button values based on their type and thresholds. // Update the pad button values based on their type and thresholds.
// With this you can use axis or triggers as buttons or vice versa // With this you can use axis or triggers as buttons or vice versa
auto p_profile = m_dev->config;
switch (keyCode) switch (keyCode)
{ {
case XInputKeyCodes::LT: case XInputKeyCodes::LT:
pressed = val > m_pad_config.ltriggerthreshold; pressed = val > p_profile->ltriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0; val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0;
break; break;
case XInputKeyCodes::RT: case XInputKeyCodes::RT:
pressed = val > m_pad_config.rtriggerthreshold; pressed = val > p_profile->rtriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0; val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0;
break; break;
case XInputKeyCodes::LSXNeg: case XInputKeyCodes::LSXNeg:
case XInputKeyCodes::LSXPos: case XInputKeyCodes::LSXPos:
case XInputKeyCodes::LSYPos: case XInputKeyCodes::LSYPos:
case XInputKeyCodes::LSYNeg: case XInputKeyCodes::LSYNeg:
pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0; val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0;
break; break;
case XInputKeyCodes::RSXNeg: case XInputKeyCodes::RSXNeg:
case XInputKeyCodes::RSXPos: case XInputKeyCodes::RSXPos:
case XInputKeyCodes::RSYPos: case XInputKeyCodes::RSYPos:
case XInputKeyCodes::RSYNeg: case XInputKeyCodes::RSYNeg:
pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0; val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0;
break; break;
default: // normal button (should in theory also support sensitive buttons) default: // normal button (should in theory also support sensitive buttons)
pressed = val > 0; pressed = val > 0;
@ -293,10 +295,6 @@ bool xinput_pad_handler::Init()
if (!is_init) if (!is_init)
return false; return false;
m_pad_config.load();
if (!m_pad_config.exist())
m_pad_config.save();
return true; return true;
} }
@ -316,8 +314,9 @@ void xinput_pad_handler::ThreadProc()
{ {
for (auto &bind : bindings) for (auto &bind : bindings)
{ {
auto device = bind.first; m_dev = bind.first;
auto padnum = device->deviceNumber; auto padnum = m_dev->deviceNumber;
auto profile = m_dev->config;
auto pad = bind.second; auto pad = bind.second;
result = (*xinputGetState)(padnum, &state); result = (*xinputGetState)(padnum, &state);
@ -333,7 +332,7 @@ void xinput_pad_handler::ThreadProc()
last_connection_status[padnum] = false; last_connection_status[padnum] = false;
connected--; connected--;
} }
return; continue;
case ERROR_SUCCESS: case ERROR_SUCCESS:
if (last_connection_status[padnum] == false) if (last_connection_status[padnum] == false)
@ -364,7 +363,7 @@ void xinput_pad_handler::ThreadProc()
} }
// used to get the absolute value of an axis // used to get the absolute value of an axis
float stick_val[4]; s32 stick_val[4];
// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++) for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++)
@ -388,13 +387,13 @@ void xinput_pad_handler::ThreadProc()
u16 lx, ly, rx, ry; u16 lx, ly, rx, ry;
// Normalize our two stick's axis based on the thresholds // Normalize our two stick's axis based on the thresholds
std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], m_pad_config.lstickdeadzone); std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone);
std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone); std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone);
if (m_pad_config.padsquircling != 0) if (profile->padsquircling != 0)
{ {
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
} }
pad->m_sticks[0].m_value = lx; pad->m_sticks[0].m_value = lx;
@ -410,19 +409,19 @@ void xinput_pad_handler::ThreadProc()
// The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor. // The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor.
// The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535. // The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535.
int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0; int idx_l = profile->switch_vibration_motors ? 1 : 0;
int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1; int idx_s = profile->switch_vibration_motors ? 0 : 1;
int speed_large = m_pad_config.enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; int speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min;
int speed_small = m_pad_config.enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; int speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min;
device->newVibrateData = device->newVibrateData || device->largeVibrate != speed_large || device->smallVibrate != speed_small; m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small;
device->largeVibrate = speed_large; m_dev->largeVibrate = speed_large;
device->smallVibrate = speed_small; m_dev->smallVibrate = speed_small;
// XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable. // XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable.
if (device->newVibrateData && (clock() - device->last_vibration > 20)) if (m_dev->newVibrateData && (clock() - m_dev->last_vibration > 20))
{ {
XINPUT_VIBRATION vibrate; XINPUT_VIBRATION vibrate;
vibrate.wLeftMotorSpeed = speed_large; vibrate.wLeftMotorSpeed = speed_large;
@ -430,8 +429,8 @@ void xinput_pad_handler::ThreadProc()
if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS) if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS)
{ {
device->newVibrateData = false; m_dev->newVibrateData = false;
device->last_vibration = clock(); m_dev->last_vibration = clock();
} }
} }
@ -464,10 +463,15 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::st
if (device_number < 0) if (device_number < 0)
return false; return false;
std::shared_ptr<XInputDevice> device_id = std::make_shared<XInputDevice>(); std::shared_ptr<XInputDevice> x_device = std::make_shared<XInputDevice>();
device_id->deviceNumber = static_cast<u32>(device_number); x_device->deviceNumber = static_cast<u32>(device_number);
m_pad_config.load(); int index = static_cast<int>(bindings.size());
m_pad_configs[index].load();
x_device->config = &m_pad_configs[index];
pad_config* p_profile = x_device->config;
if (p_profile == nullptr)
return false;
pad->Init pad->Init
( (
@ -477,29 +481,29 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::st
CELL_PAD_DEV_TYPE_STANDARD CELL_PAD_DEV_TYPE_STANDARD
); );
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.up), CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.down), CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.left), CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.right), CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.start), CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.select), CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.l3), CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.r3), CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l1), CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r1), CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.cross), CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.square), CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l2), CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r2), CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, m_pad_config.ls_left), FindKeyCode(button_list, m_pad_config.ls_right)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, m_pad_config.ls_down), FindKeyCode(button_list, m_pad_config.ls_up)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, m_pad_config.rs_left), FindKeyCode(button_list, m_pad_config.rs_right)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, m_pad_config.rs_down), FindKeyCode(button_list, m_pad_config.rs_up)); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up));
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399);
@ -509,7 +513,7 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::st
pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0); pad->m_vibrateMotors.emplace_back(false, 0);
bindings.emplace_back(device_id, pad); bindings.emplace_back(x_device, pad);
return true; return true;
} }

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "stdafx.h"
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "Emu/Io/PadHandler.h" #include "Emu/Io/PadHandler.h"
#define NOMINMAX #define NOMINMAX
@ -95,6 +94,7 @@ class xinput_pad_handler final : public PadHandlerBase
u8 largeVibrate{ 0 }; u8 largeVibrate{ 0 };
u8 smallVibrate{ 0 }; u8 smallVibrate{ 0 };
clock_t last_vibration{ 0 }; clock_t last_vibration{ 0 };
pad_config* config{ nullptr };
}; };
public: public:
@ -109,6 +109,7 @@ public:
void ThreadProc() override; void ThreadProc() override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
void init_config(pad_config* cfg, const std::string& name) override;
private: private:
typedef void (WINAPI * PFN_XINPUTENABLE)(BOOL); typedef void (WINAPI * PFN_XINPUTENABLE)(BOOL);
@ -121,15 +122,16 @@ private:
std::array<u16, XInputKeyCodes::KeyCodeCount> GetButtonValues(const XINPUT_STATE& state); std::array<u16, XInputKeyCodes::KeyCodeCount> GetButtonValues(const XINPUT_STATE& state);
void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override;
bool is_init; bool is_init{ false };
HMODULE library; HMODULE library{ nullptr };
PFN_XINPUTGETSTATE xinputGetState; PFN_XINPUTGETSTATE xinputGetState{ nullptr };
PFN_XINPUTSETSTATE xinputSetState; PFN_XINPUTSETSTATE xinputSetState{ nullptr };
PFN_XINPUTENABLE xinputEnable; PFN_XINPUTENABLE xinputEnable{ nullptr };
PFN_XINPUTGETBATTERYINFORMATION xinputGetBatteryInformation; PFN_XINPUTGETBATTERYINFORMATION xinputGetBatteryInformation{ nullptr };
std::vector<u32> blacklist; std::vector<u32> blacklist;
std::vector<std::pair<std::shared_ptr<XInputDevice>, std::shared_ptr<Pad>>> bindings; std::vector<std::pair<std::shared_ptr<XInputDevice>, std::shared_ptr<Pad>>> bindings;
std::shared_ptr<XInputDevice> m_dev;
// holds internal controller state change // holds internal controller state change
XINPUT_STATE state; XINPUT_STATE state;