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;
}
void init_config(pad_config* /*cfg*/, const std::string& /*name*/) override
{
}
std::vector<std::string> ListDevices() override
{
std::vector<std::string> nulllist;
@ -17,7 +21,7 @@ public:
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;
}
@ -25,5 +29,4 @@ public:
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 "../../Utilities/Config.h"
#include "../../Utilities/types.h"
#include "Emu/System.h"
// 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 = "";
cfg::string ls_left { this, "Left Stick Left", "" };
@ -327,7 +369,7 @@ protected:
bool b_has_deadzones = false;
bool b_has_rumble = false;
bool b_has_config = false;
pad_config m_pad_config;
std::array<pad_config, MAX_GAMEPADS> m_pad_configs;
template <typename T>
T lerp(T v0, T v1, T t) {
@ -335,245 +377,52 @@ protected:
}
// 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)
{
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;
};
int FindKeyCode(std::unordered_map<u32, std::string> map, const cfg::string& name, bool fallback = true);
// 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)
{
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;
};
long FindKeyCode(std::unordered_map<u64, std::string> map, const cfg::string& name, bool fallback = true);
// 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)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return it->first;
}
int FindKeyCodeByString(std::unordered_map<u32, std::string> map, const std::string& name, bool fallback = true);
if (fallback)
{
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));
}
};
// 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);
// Get new scaled value between 0 and 255 based on its minimum and 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;
};
float ScaleStickInput(s32 raw_value, int minimum, int maximum);
// Get new scaled value between -255 and 255 based on its minimum and maximum
float ScaleStickInput2(s32 raw_value, int minimum, int maximum)
{
// value based on max range converted to [0, 1]
float val = float(Clamp(raw_value, minimum, maximum) - minimum) / float(abs(maximum) + abs(minimum));
return (510.0f * val) - 255.0f;
};
float ScaleStickInput2(s32 raw_value, int minimum, int maximum);
// Get normalized trigger value based on the range defined by a threshold
u16 NormalizeTriggerInput(u16 value, int 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 NormalizeDirectedInput(u16 raw_value, float threshold, float maximum)
{
if (threshold >= maximum || maximum <= 0)
{
return static_cast<u16>(0);
}
u16 NormalizeDirectedInput(u16 raw_value, s32 threshold, s32 maximum);
float val = float(Clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1]
if (threshold <= 0)
{
return static_cast<u16>(255.0f * val);
}
else
{
float thresh = threshold / maximum; // threshold converted to [0, 1]
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);
}
}
u16 NormalizeStickInput(u16 raw_value, int threshold, bool ignore_threshold = false);
// 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> 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) );
};
std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone);
// get clamped value between min and 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);
};
s32 Clamp(f32 input, s32 min, s32 max);
// get clamped value between 0 and 255
u16 Clamp0To255(f32 input)
{
return static_cast<u16>(Clamp(input, 0, 255));
};
u16 Clamp0To255(f32 input);
// get clamped value between 0 and 1023
u16 Clamp0To1023(f32 input)
{
return static_cast<u16>(Clamp(input, 0, 1023));
}
u16 Clamp0To1023(f32 input);
// input has to be [-1,1]. result will be [0,255]
u16 ConvertAxis(float value)
{
return static_cast<u16>((value + 1.0)*(255.0 / 2.0));
};
u16 ConvertAxis(float value);
// 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> ConvertToSquirclePoint(u16 inX, u16 inY, float 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);
}
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY, int squircle_factor);
public:
s32 thumb_min = 0;
@ -584,24 +433,32 @@ public:
s32 vibration_max = 255;
u32 connected = 0;
virtual bool Init() { return true; };
virtual ~PadHandlerBase() = default;
pad_handler m_type = pad_handler::null;
//Does it have GUI Config?
bool has_config() { return b_has_config; };
bool has_rumble() { return b_has_rumble; };
bool has_deadzones() { return b_has_deadzones; };
pad_config* GetConfig() { return &m_pad_config; };
bool has_config();
bool has_rumble();
bool has_deadzones();
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)
virtual void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) {};
virtual void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) {};
virtual void GetNextButtonPress(const std::string& /*padId*/, const std::function<void(u16, std::string, int[])>& /*callback*/, bool /*get_blacklist*/ = false, std::vector<std::string> /*buttons*/ = {}) {};
virtual void TestVibration(const std::string& /*padId*/, u32 /*largeMotor*/, u32 /*smallMotor*/) {};
//Return list of devices for that handler
virtual std::vector<std::string> ListDevices() = 0;
//Callback called during pad_thread::ThreadFunc
virtual void ThreadProc() = 0;
//Binds a Pad to a device
virtual bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) = 0;
virtual bool bindPadToDevice(std::shared_ptr<Pad> /*pad*/, const std::string& /*device*/) = 0;
virtual void init_config(pad_config* /*cfg*/, const std::string& /*name*/) = 0;
private:
virtual void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) {};
virtual void TranslateButtonPress(u64 /*keyCode*/, bool& /*pressed*/, u16& /*val*/, bool /*ignore_threshold*/ = false) {};
protected:
void init_configs();
};

View File

@ -145,7 +145,6 @@ void fmt_class_string<video_aspect>::format(std::string& out, u64 arg)
});
}
template <>
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 "rpcs3qt/pad_settings_dialog.h"
#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
thumb_min = 0;
thumb_max = 255;
@ -92,52 +91,6 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false)
vibration_min = 0;
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
b_has_config = true;
b_has_rumble = true;
@ -147,6 +100,54 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false)
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)
{
if (get_blacklist)
@ -227,6 +228,21 @@ void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u3
device->largeVibrate = largeMotor;
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 :)
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.
// With this you can use axis or triggers as buttons or vice versa
auto p_profile = m_dev->config;
switch (keyCode)
{
case DS4KeyCodes::L2:
pressed = val > m_pad_config.ltriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0;
pressed = val > p_profile->ltriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0;
break;
case DS4KeyCodes::R2:
pressed = val > m_pad_config.rtriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0;
pressed = val > p_profile->rtriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0;
break;
case DS4KeyCodes::LSXNeg:
case DS4KeyCodes::LSXPos:
case DS4KeyCodes::LSYNeg:
case DS4KeyCodes::LSYPos:
pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone);
val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0;
break;
case DS4KeyCodes::RSXNeg:
case DS4KeyCodes::RSXPos:
case DS4KeyCodes::RSYNeg:
case DS4KeyCodes::RSYPos:
pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone);
val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0;
break;
default: // normal button (should in theory also support sensitive buttons)
pressed = val > 0;
@ -406,8 +423,8 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr<DS4Device>& device,
pad->m_cable_state = device->cableState;
auto buf = device->padData;
auto button_values = GetButtonValues(device);
auto p_profile = device->config;
// Translate any corresponding keycodes to our normal DS3 buttons and triggers
for (auto & btn : pad->m_buttons)
@ -428,7 +445,7 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr<DS4Device>& device,
#endif
// 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)
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;
// 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(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone);
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], 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(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling);
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, p_profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, p_profile->padsquircling);
}
ly = 255 - ly;
@ -654,6 +671,10 @@ ds4_pad_handler::~ds4_pad_handler()
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};
// write rumble state
if (device->btCon)
@ -663,9 +684,9 @@ int ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device>& device)
outputBuf[3] = 0x07;
outputBuf[6] = device->smallVibrate;
outputBuf[7] = device->largeVibrate;
outputBuf[8] = m_pad_config.colorR; // red
outputBuf[9] = m_pad_config.colorG; // green
outputBuf[10] = m_pad_config.colorB; // blue
outputBuf[8] = p_profile->colorR; // red
outputBuf[9] = p_profile->colorG; // green
outputBuf[10] = p_profile->colorB; // blue
// 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
@ -690,9 +711,9 @@ int ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device>& device)
outputBuf[1] = 0x07;
outputBuf[4] = device->smallVibrate;
outputBuf[5] = device->largeVibrate;
outputBuf[6] = m_pad_config.colorR; // red
outputBuf[7] = m_pad_config.colorG; // green
outputBuf[8] = m_pad_config.colorB; // blue
outputBuf[6] = p_profile->colorR; // red
outputBuf[7] = p_profile->colorG; // green
outputBuf[8] = p_profile->colorB; // blue
outputBuf[9] = device->led_delay_on;
outputBuf[10] = device->led_delay_off;
@ -734,10 +755,6 @@ bool ds4_pad_handler::Init()
else
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;
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)
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
(
@ -774,23 +796,23 @@ 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
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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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->l2), CELL_PAD_CTRL_L2);
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, p_profile->up), CELL_PAD_CTRL_UP);
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, p_profile->left), CELL_PAD_CTRL_LEFT);
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, p_profile->square), CELL_PAD_CTRL_SQUARE);
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, p_profile->circle), CELL_PAD_CTRL_CIRCLE);
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, p_profile->l1), CELL_PAD_CTRL_L1);
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, p_profile->select), CELL_PAD_CTRL_SELECT);
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, p_profile->l3), CELL_PAD_CTRL_L3);
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, 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_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
@ -798,10 +820,10 @@ bool ds4_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::strin
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_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_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_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_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_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, 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, 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, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up));
pad->m_vibrateMotors.emplace_back(true, 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++)
{
std::shared_ptr<DS4Device> device = bindings[i].first;
m_dev = bindings[i].first;
auto thepad = bindings[i].second;
auto profile = m_dev->config;
if (device->hidDevice == nullptr)
if (m_dev->hidDevice == nullptr)
{
// 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 (last_connection_status[i] == false)
@ -831,10 +854,10 @@ void ds4_pad_handler::ThreadProc()
connected++;
}
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;
if (!device->hasCalibData)
device->hasCalibData = GetCalibrationData(device);
if (!m_dev->hasCalibData)
m_dev->hasCalibData = GetCalibrationData(m_dev);
}
else
{
@ -856,53 +879,53 @@ void ds4_pad_handler::ThreadProc()
connected++;
}
DS4DataStatus status = GetRawData(device);
DS4DataStatus status = GetRawData(m_dev);
if (status == DS4DataStatus::ReadError)
{
// this also can mean disconnected, either way deal with it on next loop and reconnect
hid_close(device->hidDevice);
device->hidDevice = nullptr;
hid_close(m_dev->hidDevice);
m_dev->hidDevice = nullptr;
continue;
}
// Attempt to send rumble no matter what
int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0;
int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1;
int idx_l = profile->switch_vibration_motors ? 1 : 0;
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_small = m_pad_config.enable_vibration_motor_small ? thepad->m_vibrateMotors[idx_s].m_value : vibration_min;
int speed_large = profile->enable_vibration_motor_large ? thepad->m_vibrateMotors[idx_l].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 lowBattery = device->batteryLevel < 2;
bool isBlinking = device->led_delay_on > 0 || device->led_delay_off > 0;
bool wireless = m_dev->cableState < 1;
bool lowBattery = m_dev->batteryLevel < 2;
bool isBlinking = m_dev->led_delay_on > 0 || m_dev->led_delay_off > 0;
bool newBlinkData = false;
// we are now wired or have okay battery level -> stop blinking
if (isBlinking && !(wireless && lowBattery))
{
device->led_delay_on = 0;
device->led_delay_off = 0;
m_dev->led_delay_on = 0;
m_dev->led_delay_off = 0;
newBlinkData = true;
}
// we are now wireless and low on battery -> blink
if (!isBlinking && wireless && lowBattery)
{
device->led_delay_on = 100;
device->led_delay_off = 100;
m_dev->led_delay_on = 100;
m_dev->led_delay_off = 100;
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;
device->smallVibrate = speed_small;
m_dev->largeVibrate = speed_large;
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;
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
{
hid_device* hidDevice{ nullptr };
pad_config* config{ nullptr };
std::string path{ "" };
bool btCon{ false };
bool hasCalibData{ false };
@ -143,12 +144,14 @@ public:
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 TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
void init_config(pad_config* cfg, const std::string& name) override;
private:
bool is_init;
bool is_init = false;
std::vector<u32> blacklist;
std::vector<std::pair<std::shared_ptr<DS4Device>, std::shared_ptr<Pad>>> bindings;
std::shared_ptr<DS4Device> m_dev;
private:
std::shared_ptr<DS4Device> GetDevice(const std::string& padId);

View File

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

View File

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

View File

@ -17,8 +17,10 @@
#include <cstdio>
#include <cmath>
evdev_joystick_handler::evdev_joystick_handler()
evdev_joystick_handler::evdev_joystick_handler() : PadHandlerBase(pad_handler::evdev)
{
init_configs();
// Define border values
thumb_min = 0;
thumb_max = 255;
@ -27,47 +29,6 @@ evdev_joystick_handler::evdev_joystick_handler()
vibration_min = 0;
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
b_has_config = true;
b_has_rumble = true;
@ -82,12 +43,54 @@ evdev_joystick_handler::~evdev_joystick_handler()
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()
{
if (m_is_init)
return true;
m_pad_config.load();
m_pos_axis_config.load();
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.
// With this you can use axis or triggers as buttons or vice versa
auto profile = m_dev.config;
u32 code = static_cast<u32>(keyCode);
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))
{
pressed = value > m_pad_config.ltriggerthreshold;
value = pressed ? NormalizeTriggerInput(value, m_pad_config.ltriggerthreshold) : 0;
pressed = value > profile->ltriggerthreshold;
value = pressed ? NormalizeTriggerInput(value, profile->ltriggerthreshold) : 0;
}
else if (checkButton(m_dev.trigger_right))
{
pressed = value > m_pad_config.rtriggerthreshold;
value = pressed ? NormalizeTriggerInput(value, m_pad_config.rtriggerthreshold) : 0;
pressed = value > profile->rtriggerthreshold;
value = pressed ? NormalizeTriggerInput(value, profile->rtriggerthreshold) : 0;
}
else if (checkButtons(m_dev.axis_left))
{
pressed = value > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone);
value = pressed ? NormalizeStickInput(value, m_pad_config.lstickdeadzone, ignore_threshold) : 0;
pressed = value > (ignore_threshold ? 0 : profile->lstickdeadzone);
value = pressed ? NormalizeStickInput(value, profile->lstickdeadzone, ignore_threshold) : 0;
}
else if (checkButtons(m_dev.axis_right))
{
pressed = value > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone);
value = pressed ? NormalizeStickInput(value, m_pad_config.rstickdeadzone, ignore_threshold) : 0;
pressed = value > (ignore_threshold ? 0 : profile->rstickdeadzone);
value = pressed ? NormalizeStickInput(value, profile->rstickdeadzone, ignore_threshold) : 0;
}
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))
{
// 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);
close(fd);
@ -643,7 +647,7 @@ int evdev_joystick_handler::add_device(const std::string& device, bool in_settin
close(fd);
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) &&
libevdev_has_event_code(dev, EV_ABS, ABS_X) &&
libevdev_has_event_code(dev, EV_ABS, ABS_Y) &&
@ -680,6 +684,7 @@ void evdev_joystick_handler::ThreadProc()
for (auto& device : devices)
{
m_dev = device;
auto profile = device.config;
auto pad = device.pad;
auto axis_orientations = device.axis_orientations;
auto& dev = device.device;
@ -704,10 +709,10 @@ void evdev_joystick_handler::ThreadProc()
padnum++;
// Handle vibration
int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0;
int idx_s = m_pad_config.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_small = m_pad_config.enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min;
int idx_l = profile->switch_vibration_motors ? 1 : 0;
int idx_s = profile->switch_vibration_motors ? 0 : 1;
u16 force_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].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);
// Try to query the latest event from the joystick.
@ -832,13 +837,13 @@ void evdev_joystick_handler::ThreadProc()
u16 lx, ly, rx, ry;
// 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(rx, ry) = NormalizeStickDeadzone(device.stick_val[2], device.stick_val[3], m_pad_config.rstickdeadzone);
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], 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(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling);
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
}
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 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)
{
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
);
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(m_pad_config.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(m_pad_config.square), CELL_PAD_CTRL_SQUARE);
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(p_profile->circle), CELL_PAD_CTRL_CIRCLE);
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(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);
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, find_key(m_pad_config.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_DIGITAL1, find_key(m_pad_config.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(m_pad_config.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_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_DIGITAL1, find_key(m_pad_config.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(m_pad_config.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_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1);
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(p_profile->start), CELL_PAD_CTRL_START);
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(p_profile->l3), CELL_PAD_CTRL_L3);
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(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
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(p_profile->down), CELL_PAD_CTRL_DOWN);
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(p_profile->right), CELL_PAD_CTRL_RIGHT);
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[1] = evdevbutton(m_pad_config.ls_left);
m_dev.axis_left[2] = evdevbutton(m_pad_config.ls_up);
m_dev.axis_left[3] = evdevbutton(m_pad_config.ls_down);
m_dev.axis_right[0] = evdevbutton(m_pad_config.rs_right);
m_dev.axis_right[1] = evdevbutton(m_pad_config.rs_left);
m_dev.axis_right[2] = evdevbutton(m_pad_config.rs_up);
m_dev.axis_right[3] = evdevbutton(m_pad_config.rs_down);
m_dev.axis_left[0] = evdevbutton(p_profile->ls_right);
m_dev.axis_left[1] = evdevbutton(p_profile->ls_left);
m_dev.axis_left[2] = evdevbutton(p_profile->ls_up);
m_dev.axis_left[3] = evdevbutton(p_profile->ls_down);
m_dev.axis_right[0] = evdevbutton(p_profile->rs_right);
m_dev.axis_right[1] = evdevbutton(p_profile->rs_left);
m_dev.axis_right[2] = evdevbutton(p_profile->rs_up);
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_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
{
libevdev* device = nullptr;
libevdev* device{ nullptr };
pad_config* config{ nullptr };
std::string path;
std::shared_ptr<Pad> pad;
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_max[4] = { 0, 0, 0, 0 };
EvdevButton trigger_left = { 0, 0, 0 };
@ -328,6 +329,7 @@ public:
evdev_joystick_handler();
~evdev_joystick_handler();
void init_config(pad_config* cfg, const std::string& name) override;
bool Init() override;
std::vector<std::string> ListDevices() 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 "rpcs3qt/pad_settings_dialog.h"
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString;
@ -14,46 +10,50 @@ bool keyboard_pad_handler::Init()
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
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();
init_configs();
// set capabilities
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)
{
value = Clamp0To255(value);
@ -65,29 +65,22 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
if (button.m_keyCode != code)
continue;
//Todo: Is this flush necessary once games hit decent speeds?
if (button.m_pressed && !pressed)
{
button.m_flush = true;
}
else
{
button.m_pressed = pressed;
if (pressed)
button.m_value = value;
else
button.m_value = 0;
}
button.m_value = pressed ? value : 0;
}
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;
if (pad->m_sticks[i].m_keyCodeMin == code)
if (is_min)
m_stick_min[i] = pressed ? 128 : 0;
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")
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)
{
@ -407,29 +404,29 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::
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(m_pad_config.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(m_pad_config.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(m_pad_config.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(m_pad_config.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_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT);
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(p_profile->right), CELL_PAD_CTRL_RIGHT);
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(p_profile->start), CELL_PAD_CTRL_START);
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(p_profile->l3), CELL_PAD_CTRL_L3);
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(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, find_key(m_pad_config.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(m_pad_config.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(m_pad_config.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(m_pad_config.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->square), CELL_PAD_CTRL_SQUARE);
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(p_profile->circle), CELL_PAD_CTRL_CIRCLE);
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(p_profile->r1), CELL_PAD_CTRL_R1);
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(p_profile->r2), CELL_PAD_CTRL_R2);
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_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_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_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_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(p_profile->ls_up), find_key(p_profile->ls_down));
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(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_Y, 399);

View File

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

View File

@ -1,9 +1,10 @@
#include "stdafx.h"
#ifdef _WIN32
#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
thumb_min = 0;
thumb_max = 255;
@ -12,47 +13,6 @@ mm_joystick_handler::mm_joystick_handler() : is_init(false)
vibration_min = 0;
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
b_has_config = 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()
{
if (is_init) return true;
if (is_init)
return true;
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);
}
else
{
LOG_ERROR(GENERAL, "Driver doesn't support Joysticks");
LOG_ERROR(GENERAL, "mmjoy: Driver doesn't support Joysticks");
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;
@ -93,7 +95,6 @@ bool mm_joystick_handler::Init()
m_devices.emplace(i, dev);
}
m_pad_config.load();
is_init = true;
return true;
}
@ -102,7 +103,8 @@ std::vector<std::string> mm_joystick_handler::ListDevices()
{
std::vector<std::string> devices;
if (!Init()) return devices;
if (!Init())
return 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));
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)
{
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
);
joy_device->trigger_left = find_key(m_pad_config.l2);
joy_device->trigger_right = find_key(m_pad_config.r2);
joy_device->axis_left[0] = find_key(m_pad_config.ls_left);
joy_device->axis_left[1] = find_key(m_pad_config.ls_right);
joy_device->axis_left[2] = find_key(m_pad_config.ls_down);
joy_device->axis_left[3] = find_key(m_pad_config.ls_up);
joy_device->axis_right[0] = find_key(m_pad_config.rs_left);
joy_device->axis_right[1] = find_key(m_pad_config.rs_right);
joy_device->axis_right[2] = find_key(m_pad_config.rs_down);
joy_device->axis_right[3] = find_key(m_pad_config.rs_up);
joy_device->trigger_left = find_key(p_profile->l2);
joy_device->trigger_right = find_key(p_profile->r2);
joy_device->axis_left[0] = find_key(p_profile->ls_left);
joy_device->axis_left[1] = find_key(p_profile->ls_right);
joy_device->axis_left[2] = find_key(p_profile->ls_down);
joy_device->axis_left[3] = find_key(p_profile->ls_up);
joy_device->axis_right[0] = find_key(p_profile->rs_left);
joy_device->axis_right[1] = find_key(p_profile->rs_right);
joy_device->axis_right[2] = find_key(p_profile->rs_down);
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(m_pad_config.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(m_pad_config.square), CELL_PAD_CTRL_SQUARE);
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(p_profile->circle), CELL_PAD_CTRL_CIRCLE);
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(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_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(m_pad_config.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(m_pad_config.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(m_pad_config.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_DIGITAL1, find_key(m_pad_config.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(m_pad_config.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_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1);
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(p_profile->start), CELL_PAD_CTRL_START);
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(p_profile->l3), CELL_PAD_CTRL_L3);
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(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
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(p_profile->down), CELL_PAD_CTRL_DOWN);
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(p_profile->right), CELL_PAD_CTRL_RIGHT);
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]);
@ -197,6 +206,7 @@ void mm_joystick_handler::ThreadProc()
{
m_dev = bindings[i].first;
auto pad = bindings[i].second;
auto profile = m_dev->config;
status = joyGetPosEx(m_dev->device_id, &m_dev->device_info);
if (status != JOYERR_NOERROR)
@ -232,7 +242,7 @@ void mm_joystick_handler::ThreadProc()
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)
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;
// 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(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone);
std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone);
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(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling);
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
}
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.
// 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)
{
pressed = val > (ignore_threshold ? 0 : m_pad_config.ltriggerthreshold);
val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->ltriggerthreshold);
val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0;
}
else if (keyCode == m_dev->trigger_right)
{
pressed = val > (ignore_threshold ? 0 : m_pad_config.rtriggerthreshold);
val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->rtriggerthreshold);
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())
{
pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone);
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())
{
pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone);
val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0;
}
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)
{
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;
bool pressed = (val == pov) || (val == cw) || (ccw < 0 ? val == 36000 - std::abs(ccw) : val == ccw);
@ -540,10 +551,8 @@ int mm_joystick_handler::GetIDByName(const std::string& name)
for (auto dev : m_devices)
{
if (dev.second.device_name == name)
{
return dev.first;
}
}
return -1;
}

View File

@ -90,6 +90,7 @@ class mm_joystick_handler final : public PadHandlerBase
{
u32 device_id{ 0 };
std::string device_name{ "" };
pad_config* config{ nullptr };
JOYINFOEX device_info;
JOYCAPS device_caps;
u64 trigger_left = 0;
@ -108,6 +109,7 @@ public:
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) 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 init_config(pad_config* cfg, const std::string& name) override;
private:
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 is_init = false;
u32 supportedJoysticks = 0;
u32 m_supported_joysticks = 0;
std::vector<u64> blacklist;
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.now_connect = 0;
input_cfg.load();
g_cfg_input.load();
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;
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)
{
@ -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_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
LOG_ERROR(GENERAL, "Failed to bind device %s to handler %s", input_cfg.player_device[i]->to_string(), handler_type.to_string());
nullpad->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->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(), g_cfg_input.player[i]->device.to_string());
}
}

View File

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

View File

@ -10,16 +10,42 @@
#endif
#include "../keyboard_pad_handler.h"
#include "../Emu/Io/Null/NullPadHandler.h"
#include "../Emu/System.h"
#include <QJsonObject>
#include <QJsonDocument>
input_config input_cfg;
#include <QInputDialog>
#include <QMessageBox>
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
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
// because size policies won't work as expected (see similar bugs in Qt bugtracker)
inline void resizeComboBoxView(QComboBox* combo)
@ -55,8 +81,8 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
QVBoxLayout *dialog_layout = new QVBoxLayout();
QHBoxLayout *all_players = new QHBoxLayout();
input_cfg.from_default();
input_cfg.load();
g_cfg_input.from_default();
g_cfg_input.load();
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);
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();
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]->setFixedSize(bu_config[i]->sizeHint());
button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f);
button_layout->setContentsMargins(0,0,0,0);
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);
grp_player->setLayout(ppad_layout);
grp_player->setFixedSize(grp_player->sizeHint());
// 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++)
{
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++)
{
// 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
ChangeInputType(i);
}
@ -140,18 +173,67 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
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)
{
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
LOG_ERROR(GENERAL, "Failed to convert device string: %s", device);
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(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit);
@ -167,12 +249,13 @@ void gamepads_settings_dialog::SaveExit()
{
if (co_deviceID[i]->currentData() == -1)
{
input_cfg.player_input[i].from_default();
input_cfg.player_device[i]->from_default();
g_cfg_input.player[i]->handler.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();
}
@ -180,8 +263,8 @@ void gamepads_settings_dialog::SaveExit()
void gamepads_settings_dialog::CancelExit()
{
//Reloads config from file or defaults
input_cfg.from_default();
input_cfg.load();
g_cfg_input.from_default();
g_cfg_input.load();
QDialog::accept();
}
@ -224,10 +307,11 @@ std::shared_ptr<PadHandlerBase> gamepads_settings_dialog::GetHandler(pad_handler
void gamepads_settings_dialog::ChangeInputType(int player)
{
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
if (!input_cfg.player_input[player].from_string(handler))
if (!g_cfg_input.player[player]->handler.from_string(handler))
{
//Something went wrong
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
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();
// 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);
}
// 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]);
bu_config[player]->setEnabled(device_found && cur_pad_handler->has_config());
resizeComboBoxView(co_profile[player]);
}
void gamepads_settings_dialog::ClickConfigButton(int player)
{
// 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())
{
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();
}
}

View File

@ -12,52 +12,6 @@
#include "../../Utilities/File.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
{
const int MAX_PLAYERS = 7;
@ -72,7 +26,9 @@ protected:
protected:
QComboBox *co_inputtype[7];
QComboBox *co_deviceID[7];
QComboBox *co_profile[7];
QPushButton *bu_config[7];
QPushButton *bu_new_profile[7];
public:
gamepads_settings_dialog(QWidget* parent);

View File

@ -321,6 +321,17 @@ QStringList gui_settings::GetConfigEntries()
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)
{
QSettings target(ComputeSettingsDir() + friendlyName + ".ini", QSettings::Format::IniFormat);

View File

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

View File

@ -13,11 +13,9 @@
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString;
pad_settings_dialog::pad_settings_dialog(const std::string& device, 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)
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_device_name(device), m_handler(handler), m_handler_type(handler->m_type)
{
m_handler_cfg->load();
ui->setupUi(this);
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_palette = ui->b_left->palette(); // save normal palette
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);
std::string cfg_name = PadHandlerBase::get_config_dir(m_handler_type) + profile + ".yml";
// Adjust to the different pad handlers
if (m_handler_cfg->cfg_type == "keyboard")
if (m_handler_type == pad_handler::keyboard)
{
setWindowTitle(tr("Configure Keyboard"));
m_handler_type = handler_type::handler_type_keyboard;
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")
{
setWindowTitle(tr("Configure XInput"));
m_handler_type = handler_type::handler_type_xinput;
}
else if (m_handler_cfg->cfg_type == "ds4")
else if (m_handler_type == pad_handler::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"));
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"));
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
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;
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)
{
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
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_left, m_handler_cfg.ltriggerthreshold, 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_right->setRange(0, m_handler->trigger_max);
// Enable Stick Deadzones
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_left, m_handler_cfg.lstickdeadzone, 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);
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);
};
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_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_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_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_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_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_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_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_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_l3, ui->b_shift_l3, &m_handler_cfg->l3);
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_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_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_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_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_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_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_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_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_triangle, ui->b_triangle, &m_handler_cfg->triangle);
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_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_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_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_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_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);
m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters);
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)
{
if (m_handler_type != handler_type::handler_type_keyboard)
if (m_handler_type != pad_handler::keyboard)
{
return;
}
@ -370,7 +378,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent)
void pad_settings_dialog::mousePressEvent(QMouseEvent* event)
{
if (m_handler_type != handler_type::handler_type_keyboard)
if (m_handler_type != pad_handler::keyboard)
{
return;
}
@ -407,17 +415,17 @@ void pad_settings_dialog::UpdateLabel(bool is_reset)
{
if (m_handler->has_rumble())
{
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);
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);
}
if (m_handler->has_deadzones())
{
ui->slider_trigger_left->setValue(m_handler_cfg->ltriggerthreshold);
ui->slider_trigger_right->setValue(m_handler_cfg->rtriggerthreshold);
ui->slider_stick_left->setValue(m_handler_cfg->lstickdeadzone);
ui->slider_stick_right->setValue(m_handler_cfg->rstickdeadzone);
ui->slider_trigger_left->setValue(m_handler_cfg.ltriggerthreshold);
ui->slider_trigger_right->setValue(m_handler_cfg.rtriggerthreshold);
ui->slider_stick_left->setValue(m_handler_cfg.lstickdeadzone);
ui->slider_stick_right->setValue(m_handler_cfg.rstickdeadzone);
}
}
@ -450,20 +458,20 @@ void pad_settings_dialog::SaveConfig()
if (m_handler->has_rumble())
{
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->switch_vibration_motors.set(ui->chb_vibration_switch->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.switch_vibration_motors.set(ui->chb_vibration_switch->isChecked());
}
if (m_handler->has_deadzones())
{
m_handler_cfg->ltriggerthreshold.set(ui->slider_trigger_left->value());
m_handler_cfg->rtriggerthreshold.set(ui->slider_trigger_right->value());
m_handler_cfg->lstickdeadzone.set(ui->slider_stick_left->value());
m_handler_cfg->rstickdeadzone.set(ui->slider_stick_right->value());
m_handler_cfg.ltriggerthreshold.set(ui->slider_trigger_left->value());
m_handler_cfg.rtriggerthreshold.set(ui->slider_trigger_right->value());
m_handler_cfg.lstickdeadzone.set(ui->slider_stick_left->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)
@ -476,7 +484,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
return;
case button_ids::id_reset_parameters:
ReactivateButtons();
m_handler_cfg->from_default();
m_handler_cfg.from_default();
UpdateLabel(true);
return;
case button_ids::id_blacklist:

View File

@ -17,6 +17,12 @@
#ifdef _WIN32
#include "xinput_pad_handler.h"
#endif
#ifdef _MSC_VER
#include "mm_joystick_handler.h"
#endif
#ifdef HAVE_LIBEVDEV
#include "evdev_joystick_handler.h"
#endif
#include "ds4_pad_handler.h"
namespace Ui
@ -72,15 +78,6 @@ class pad_settings_dialog : public QDialog
id_cancel
};
enum handler_type
{
handler_type_keyboard,
handler_type_xinput,
handler_type_ds4,
handler_type_mmjoy,
handler_type_evdev
};
struct pad_button
{
cfg::string* cfg_name;
@ -109,9 +106,9 @@ private:
QPalette m_palette;
// Pad Handlers
pad_handler m_handler_type;
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;
// Remap Timer
@ -129,7 +126,7 @@ private:
void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y);
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();
/** Handle keyboard handler input */

View File

@ -1,12 +1,11 @@
#ifdef _MSC_VER
#include "xinput_pad_handler.h"
#include "rpcs3qt/pad_settings_dialog.h"
xinput_pad_handler::xinput_pad_handler() :
library(nullptr), xinputGetState(nullptr), xinputEnable(nullptr),
xinputSetState(nullptr), xinputGetBatteryInformation(nullptr), is_init(false)
xinput_pad_handler::xinput_pad_handler() : PadHandlerBase(pad_handler::xinput)
{
init_configs();
// Define border values
thumb_min = -32768;
thumb_max = 32767;
@ -15,47 +14,6 @@ xinput_pad_handler::xinput_pad_handler() :
vibration_min = 0;
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
b_has_config = true;
b_has_rumble = true;
@ -70,6 +28,49 @@ xinput_pad_handler::~xinput_pad_handler()
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)
{
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.
// With this you can use axis or triggers as buttons or vice versa
auto p_profile = m_dev->config;
switch (keyCode)
{
case XInputKeyCodes::LT:
pressed = val > m_pad_config.ltriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0;
pressed = val > p_profile->ltriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0;
break;
case XInputKeyCodes::RT:
pressed = val > m_pad_config.rtriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0;
pressed = val > p_profile->rtriggerthreshold;
val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0;
break;
case XInputKeyCodes::LSXNeg:
case XInputKeyCodes::LSXPos:
case XInputKeyCodes::LSYPos:
case XInputKeyCodes::LSYNeg:
pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone);
val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0;
break;
case XInputKeyCodes::RSXNeg:
case XInputKeyCodes::RSXPos:
case XInputKeyCodes::RSYPos:
case XInputKeyCodes::RSYNeg:
pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone);
val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0;
pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone);
val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0;
break;
default: // normal button (should in theory also support sensitive buttons)
pressed = val > 0;
@ -293,10 +295,6 @@ bool xinput_pad_handler::Init()
if (!is_init)
return false;
m_pad_config.load();
if (!m_pad_config.exist())
m_pad_config.save();
return true;
}
@ -316,8 +314,9 @@ void xinput_pad_handler::ThreadProc()
{
for (auto &bind : bindings)
{
auto device = bind.first;
auto padnum = device->deviceNumber;
m_dev = bind.first;
auto padnum = m_dev->deviceNumber;
auto profile = m_dev->config;
auto pad = bind.second;
result = (*xinputGetState)(padnum, &state);
@ -333,7 +332,7 @@ void xinput_pad_handler::ThreadProc()
last_connection_status[padnum] = false;
connected--;
}
return;
continue;
case ERROR_SUCCESS:
if (last_connection_status[padnum] == false)
@ -364,7 +363,7 @@ void xinput_pad_handler::ThreadProc()
}
// 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)
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;
// 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(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone);
std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone);
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(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling);
std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling);
std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling);
}
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 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_s = m_pad_config.switch_vibration_motors ? 0 : 1;
int idx_l = profile->switch_vibration_motors ? 1 : 0;
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_small = m_pad_config.enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].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 = 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;
device->smallVibrate = speed_small;
m_dev->largeVibrate = speed_large;
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.
if (device->newVibrateData && (clock() - device->last_vibration > 20))
if (m_dev->newVibrateData && (clock() - m_dev->last_vibration > 20))
{
XINPUT_VIBRATION vibrate;
vibrate.wLeftMotorSpeed = speed_large;
@ -430,8 +429,8 @@ void xinput_pad_handler::ThreadProc()
if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS)
{
device->newVibrateData = false;
device->last_vibration = clock();
m_dev->newVibrateData = false;
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)
return false;
std::shared_ptr<XInputDevice> device_id = std::make_shared<XInputDevice>();
device_id->deviceNumber = static_cast<u32>(device_number);
std::shared_ptr<XInputDevice> x_device = std::make_shared<XInputDevice>();
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
(
@ -477,29 +481,29 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::st
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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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, m_pad_config.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_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP);
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, p_profile->left), CELL_PAD_CTRL_LEFT);
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, p_profile->start), CELL_PAD_CTRL_START);
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, p_profile->l3), CELL_PAD_CTRL_L3);
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, p_profile->l1), CELL_PAD_CTRL_L1);
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, 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, p_profile->cross), CELL_PAD_CTRL_CROSS);
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, p_profile->square), CELL_PAD_CTRL_SQUARE);
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, p_profile->l2), CELL_PAD_CTRL_L2);
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_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_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_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_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_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, 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, 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, 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_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(false, 0);
bindings.emplace_back(device_id, pad);
bindings.emplace_back(x_device, pad);
return true;
}

View File

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