Merge branch 'master' into stdc++-auto-checker

This commit is contained in:
Ani 2018-12-23 21:49:57 +00:00 committed by GitHub
commit fc25df84f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 392 additions and 104 deletions

View file

@ -316,7 +316,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
// * Installed
// We will go with the easy path of Installed, and that's it.
auto statuses = {SCE_NP_TROPHY_STATUS_NOT_INSTALLED,
auto statuses = {SCE_NP_TROPHY_STATUS_INSTALLED,
SCE_NP_TROPHY_STATUS_PROCESSING_SETUP,
SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS,
SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE,

View file

@ -448,7 +448,7 @@ public:
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 GetNextButtonPress(const std::string& /*padId*/, const std::function<void(u16, std::string, std::string, int[])>& /*callback*/, const std::function<void(std::string)>& /*fail_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;

View file

@ -494,8 +494,85 @@ bool Emulator::BootRsxCapture(const std::string& path)
return true;
}
void Emulator::LimitCacheSize()
{
const std::string cache_location = Emulator::GetHdd1Dir() + "/cache";
if (!fs::is_dir(cache_location))
{
LOG_WARNING(GENERAL, "Cache does not exist (%s)", cache_location);
return;
}
const u64 size = fs::get_dir_size(cache_location);
const u64 max_size = static_cast<u64>(g_cfg.vfs.cache_max_size) * 1024 * 1024;
if (max_size == 0) // Everything must go, so no need to do checks
{
fs::remove_all(cache_location, false);
LOG_SUCCESS(GENERAL, "Cleared disk cache");
return;
}
if (size <= max_size)
{
LOG_TRACE(GENERAL, "Cache size below limit: %llu/%llu", size, max_size);
return;
}
LOG_SUCCESS(GENERAL, "Cleaning disk cache...");
std::vector<fs::dir_entry> file_list{};
fs::dir cache_dir{};
if (!cache_dir.open(cache_location))
{
LOG_ERROR(GENERAL, "Could not open cache directory");
return;
}
// retrieve items to delete
for (const auto &item : cache_dir)
{
if (item.name != "." && item.name != "..")
file_list.push_back(item);
}
cache_dir.close();
// sort oldest first
std::sort(file_list.begin(), file_list.end(), [](auto left, auto right)
{
return left.mtime < right.mtime;
});
// keep removing until cache is empty or enough bytes have been cleared
// cache is cleared down to 80% of limit to increase interval between clears
const u64 to_remove = static_cast<u64>(size - max_size * 0.8);
u64 removed = 0;
for (const auto &item : file_list)
{
const std::string &name = cache_location + "/" + item.name;
const u64 item_size = fs::is_dir(name) ? fs::get_dir_size(name) : item.size;
if (fs::is_dir(name))
{
fs::remove_all(name, true);
}
else
{
fs::remove_file(name);
}
removed += item_size;
if (removed >= to_remove)
break;
}
LOG_SUCCESS(GENERAL, "Cleaned disk cache, removed %.2f MB", size / 1024.0 / 1024.0);
}
bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
{
if (g_cfg.vfs.limit_cache_size)
LimitCacheSize();
static const char* boot_list[] =
{
"/PS3_GAME/USRDIR/EBOOT.BIN",
@ -571,6 +648,11 @@ std::string Emulator::GetHddDir()
return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", GetEmuDir());
}
std::string Emulator::GetHdd1Dir()
{
return fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", GetEmuDir());
}
std::string Emulator::GetSfoDirFromGamePath(const std::string& game_path, const std::string& user)
{
if (fs::is_file(game_path + "/PS3_DISC.SFB"))

View file

@ -189,6 +189,7 @@ struct EmuCallbacks
std::function<void()> on_ready;
std::function<void()> exit;
std::function<void()> reset_pads;
std::function<void(bool)> enable_pads;
std::function<void(s32, s32)> handle_taskbar_progress; // (type, value) type: 0 for reset, 1 for increment, 2 for set_limit
std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler;
std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler;
@ -317,6 +318,9 @@ public:
private:
static std::string GetEmuDir();
static std::string GetHdd1Dir();
void LimitCacheSize();
public:
static std::string GetHddDir();
static std::string GetSfoDirFromGamePath(const std::string& game_path, const std::string& user);
@ -404,6 +408,9 @@ struct cfg_root : cfg::node
cfg::_bool host_root{this, "Enable /host_root/"};
cfg::_bool init_dirs{this, "Initialize Directories", true};
cfg::_bool limit_cache_size{this, "Limit disk cache size", false};
cfg::_int<0, 10240> cache_max_size{this, "Disk cache maximum size (MB)", 5120};
} vfs{this};
struct node_video : cfg::node

View file

@ -140,6 +140,7 @@
"system": {
"sysLangBox": "Some games may fail to boot if the system language is not available in the game itself.\nOther games will switch language automatically to what is selected here.\nIt is recommended leaving this on a language supported by the game.",
"enterButtonAssignment": "The button used for enter/accept/confirm in system dialogs.\nChange this to use the circle button instead, which is the default configuration on japanese systems and in many japanese games.\nIn these cases having the cross button assigned can often lead to confusion.",
"enableHostRoot": "Required for some Homebrew.\nIf unsure, don't use this option."
"enableHostRoot": "Required for some Homebrew.\nIf unsure, don't use this option.",
"limitCacheSize": "Automatically removes older files from disk cache on boot if it grows larger than the specified value.\nGames can use the cache folder to temporarily store data outside of system memory. It is not used for long term storage."
}
}

View file

@ -96,7 +96,8 @@ ds4_pad_handler::ds4_pad_handler() : PadHandlerBase(pad_handler::ds4)
b_has_rumble = true;
b_has_deadzones = true;
m_name_string = "Ds4 Pad #";
m_name_string = "DS4 Pad #";
m_max_devices = CELL_PAD_MAX_PORT_NUM;
m_trigger_threshold = trigger_max / 2;
m_thumb_threshold = thumb_max / 2;
@ -150,14 +151,14 @@ void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name)
cfg->from_default();
}
void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons)
void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{
if (get_blacklist)
blacklist.clear();
std::shared_ptr<DS4Device> device = GetDevice(padId);
std::shared_ptr<DS4Device> device = GetDevice(padId, true);
if (device == nullptr || device->hidDevice == nullptr)
return;
return fail_callback(padId);
// Now that we have found a device, get its status
DS4DataStatus status = GetRawData(device);
@ -167,7 +168,7 @@ void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::fu
// this also can mean disconnected, either way deal with it on next loop and reconnect
hid_close(device->hidDevice);
device->hidDevice = nullptr;
return;
return fail_callback(padId);
}
// return if nothing new has happened. ignore this to get the current state for blacklist
@ -215,9 +216,9 @@ void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::fu
int preview_values[6] = { data[L2], data[R2], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] };
if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values);
return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else
return callback(0, "", preview_values);
return callback(0, "", padId, preview_values);
}
void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor)
@ -249,7 +250,7 @@ void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u3
SendVibrateData(device);
}
std::shared_ptr<ds4_pad_handler::DS4Device> ds4_pad_handler::GetDevice(const std::string& padId)
std::shared_ptr<ds4_pad_handler::DS4Device> ds4_pad_handler::GetDevice(const std::string& padId, bool try_reconnect)
{
if (!Init())
return nullptr;
@ -261,11 +262,22 @@ std::shared_ptr<ds4_pad_handler::DS4Device> ds4_pad_handler::GetDevice(const std
std::string pad_serial = padId.substr(pos + 9);
std::shared_ptr<DS4Device> device = nullptr;
int i = 0; // Controllers 1-n in GUI
for (auto& cur_control : controllers)
{
if (pad_serial == cur_control.first)
if (pad_serial == std::to_string(++i) || pad_serial == cur_control.first)
{
device = cur_control.second;
if (try_reconnect && device && !device->hidDevice)
{
device->hidDevice = hid_open_path(device->path.c_str());
if (device->hidDevice)
{
hid_set_nonblocking(device->hidDevice, 1);
LOG_NOTICE(HLE, "DS4 device %d reconnected", i);
}
}
break;
}
}
@ -768,9 +780,9 @@ std::vector<std::string> ds4_pad_handler::ListDevices()
if (!Init())
return ds4_pads_list;
for (auto& pad : controllers)
for (size_t i = 1; i <= controllers.size(); ++i) // Controllers 1-n in GUI
{
ds4_pads_list.emplace_back(m_name_string + pad.first);
ds4_pads_list.emplace_back(m_name_string + std::to_string(i));
}
return ds4_pads_list;

View file

@ -142,7 +142,7 @@ public:
std::vector<std::string> ListDevices() override;
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[])>& buttonCallback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& buttonCallback, const std::function<void(std::string)>& fail_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;
@ -154,7 +154,7 @@ private:
std::shared_ptr<DS4Device> m_dev;
private:
std::shared_ptr<DS4Device> GetDevice(const std::string& padId);
std::shared_ptr<DS4Device> GetDevice(const std::string& padId, bool try_reconnect = false);
void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override;
void ProcessDataToPad(const std::shared_ptr<DS4Device>& ds4Device, const std::shared_ptr<Pad>& pad);
// Copies data into padData if status is NewData, otherwise buffer is untouched

View file

@ -257,7 +257,7 @@ evdev_joystick_handler::EvdevDevice* evdev_joystick_handler::get_device(const st
return &dev;
}
void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons)
void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{
if (get_blacklist)
blacklist.clear();
@ -265,7 +265,7 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const
// Get our evdev device
EvdevDevice* device = get_device(padId);
if (device == nullptr || device->device == nullptr)
return;
return fail_callback(padId);
libevdev* dev = device->device;
// Try to query the latest event from the joystick.
@ -381,20 +381,21 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const
return it != data.end() && dir == it->second.second ? it->second.first : 0;
};
int preview_values[6] =
int preview_values[6] = { 0, 0, 0, 0, 0, 0 };
if (buttons.size() == 10)
{
find_value(buttons[0]), // Left Trigger
find_value(buttons[1]), // Right Trigger
find_value(buttons[3]) - find_value(buttons[2]), // Left Stick X
find_value(buttons[5]) - find_value(buttons[4]), // Left Stick Y
find_value(buttons[7]) - find_value(buttons[6]), // Right Stick X
find_value(buttons[9]) - find_value(buttons[8]), // Right Stick Y
};
preview_values[0] = find_value(buttons[0]); // Left Trigger
preview_values[1] = find_value(buttons[1]); // Right Trigger
preview_values[2] = find_value(buttons[3]) - find_value(buttons[2]); // Left Stick X
preview_values[3] = find_value(buttons[5]) - find_value(buttons[4]); // Left Stick Y
preview_values[4] = find_value(buttons[7]) - find_value(buttons[6]); // Right Stick X
preview_values[5] = find_value(buttons[9]) - find_value(buttons[8]); // Right Stick Y
}
if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values);
return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else
return callback(0, "", preview_values);
return callback(0, "", padId, preview_values);
}
// https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp

View file

@ -338,7 +338,7 @@ public:
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override;
void Close();
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
private:

View file

@ -94,12 +94,8 @@ int main(int argc, char** argv)
{
logs::set_init();
#ifdef _WIN32
// use this instead of SetProcessDPIAware if Qt ever fully supports this on windows
// at the moment it can't display QCombobox frames for example
// I think there was an issue with gsframe if I recall correctly, so look out for that
//QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
SetProcessDPIAware();
#if defined(_WIN32) || defined(__APPLE__)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#else
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
#endif

View file

@ -283,13 +283,13 @@ void mm_joystick_handler::ThreadProc()
}
}
void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons)
void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{
if (get_blacklist)
blacklist.clear();
if (!Init())
return;
return fail_callback(padId);
static std::string cur_pad = "";
static int id = -1;
@ -301,7 +301,7 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std
if (id < 0)
{
LOG_ERROR(GENERAL, "MMJOY GetNextButtonPress for device [%s] failed with id = %d", padId, id);
return;
return fail_callback(padId);
}
}
@ -316,7 +316,7 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std
switch (status)
{
case JOYERR_UNPLUGGED:
break;
return fail_callback(padId);
case JOYERR_NOERROR:
auto data = GetButtonValues(js_info, js_caps);
@ -403,20 +403,21 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std
return static_cast<u64>(key);
};
int preview_values[6] =
int preview_values[6] = { 0, 0, 0, 0, 0, 0 };
if (buttons.size() == 10)
{
data[find_key(buttons[0])],
data[find_key(buttons[1])],
data[find_key(buttons[3])] - data[find_key(buttons[2])],
data[find_key(buttons[5])] - data[find_key(buttons[4])],
data[find_key(buttons[7])] - data[find_key(buttons[6])],
data[find_key(buttons[9])] - data[find_key(buttons[8])],
};
preview_values[0] = data[find_key(buttons[0])];
preview_values[1] = data[find_key(buttons[1])];
preview_values[2] = data[find_key(buttons[3])] - data[find_key(buttons[2])];
preview_values[3] = data[find_key(buttons[5])] - data[find_key(buttons[4])];
preview_values[4] = data[find_key(buttons[7])] - data[find_key(buttons[6])];
preview_values[5] = data[find_key(buttons[9])] - data[find_key(buttons[8])];
}
if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values);
return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else
return callback(0, "", preview_values);
return callback(0, "", padId, preview_values);
break;
}
@ -579,7 +580,7 @@ bool mm_joystick_handler::GetMMJOYDevice(int index, MMJOYDevice* dev)
LOG_NOTICE(GENERAL, "Joystick nr.%d found. Driver: %s", index, drv);
dev->device_id = index;
dev->device_name = m_name_string + std::to_string(index);
dev->device_name = m_name_string + std::to_string(index + 1); // Controllers 1-n in GUI
dev->device_info = js_info;
dev->device_caps = js_caps;

View file

@ -108,7 +108,7 @@ public:
std::vector<std::string> ListDevices() override;
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 GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void init_config(pad_config* cfg, const std::string& name) override;
private:

View file

@ -142,11 +142,21 @@ void pad_thread::Reset()
reset = active.load();
}
void pad_thread::SetEnabled(bool enabled)
{
is_enabled = enabled;
}
void pad_thread::ThreadFunc()
{
active = true;
while (active)
{
if (!is_enabled)
{
std::this_thread::sleep_for(1ms);
continue;
}
if (reset && reset.exchange(false))
{
Init();

View file

@ -24,6 +24,7 @@ public:
void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor);
void Init();
void Reset();
void SetEnabled(bool enabled);
protected:
void ThreadFunc();
@ -40,6 +41,7 @@ protected:
atomic_t<bool> active{ false };
atomic_t<bool> reset{ false };
atomic_t<bool> is_enabled{ true };
std::shared_ptr<std::thread> thread;
};

View file

@ -146,6 +146,10 @@ void rpcs3_app::InitializeCallbacks()
{
pad::get_current_handler()->Reset();
};
callbacks.enable_pads = [this](bool enable)
{
pad::get_current_handler()->SetEnabled(enable);
};
callbacks.get_kb_handler = [=]() -> std::shared_ptr<KeyboardHandlerBase>
{

View file

@ -128,6 +128,8 @@ public:
Language,
EnterButtonAssignment,
EnableHostRoot,
LimitCacheSize,
MaximumCacheSize,
// Virtual File System
emulatorLocation,
@ -330,6 +332,8 @@ private:
{ Language, { "System", "Language"}},
{ EnterButtonAssignment, { "System", "Enter button assignment"}},
{ EnableHostRoot, { "VFS", "Enable /host_root/"}},
{ LimitCacheSize, { "VFS", "Limit disk cache size"}},
{ MaximumCacheSize, { "VFS", "Disk cache maximum size (MB)"}},
// Virtual File System
{ emulatorLocation, { "VFS", "$(EmulatorDir)"}},

View file

@ -67,6 +67,8 @@ gs_frame::gs_frame(const QString& title, const QRect& geometry, QIcon appIcon, b
setSurfaceType(QSurface::VulkanSurface);
#endif
setMinimumWidth(160);
setMinimumHeight(90);
setGeometry(geometry);
setTitle(m_windowTitle);
setVisibility(Hidden);
@ -252,20 +254,26 @@ void gs_frame::delete_context(draw_context_t ctx)
int gs_frame::client_width()
{
#if defined(_WIN32) || defined(__APPLE__)
return size().width();
#else
return size().width() * devicePixelRatio();
#endif
#ifdef _WIN32
RECT rect;
if (GetClientRect(HWND(winId()), &rect))
{
return rect.right - rect.left;
}
#endif // _WIN32
return width() * devicePixelRatio();
}
int gs_frame::client_height()
{
#if defined(_WIN32) || defined(__APPLE__)
return size().height();
#else
return size().height() * devicePixelRatio();
#endif
#ifdef _WIN32
RECT rect;
if (GetClientRect(HWND(winId()), &rect))
{
return rect.bottom - rect.top;
}
#endif // _WIN32
return height() * devicePixelRatio();
}
void gs_frame::flip(draw_context_t, bool /*skip_frame*/)

View file

@ -1252,8 +1252,25 @@ void main_window::CreateConnects()
auto openPadSettings = [this]
{
auto resetPadHandlers = [this]
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads();
};
if (!Emu.IsStopped())
{
Emu.GetCallbacks().enable_pads(false);
}
pad_settings_dialog dlg(this);
connect(&dlg, &QDialog::accepted, resetPadHandlers);
dlg.exec();
if (!Emu.IsStopped())
{
Emu.GetCallbacks().enable_pads(true);
}
};
connect(ui->confPadsAct, &QAction::triggered, openPadSettings);

View file

@ -90,13 +90,14 @@ pad_settings_dialog::pad_settings_dialog(QWidget *parent)
connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeInputType);
// Combobox: Devices
connect(ui->chooseDevice, &QComboBox::currentTextChanged, [this](const QString& dev)
connect(ui->chooseDevice, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index)
{
if (dev.isEmpty())
if (index < 0)
{
return;
}
m_device_name = sstr(dev);
const pad_info info = ui->chooseDevice->itemData(index).value<pad_info>();
m_device_name = info.name;
if (!g_cfg_input.player[m_tabs->currentIndex()]->device.from_string(m_device_name))
{
// Something went wrong
@ -316,8 +317,14 @@ void pad_settings_dialog::InitButtons()
});
// Enable Button Remapping
const auto& callback = [=](u16 val, std::string name, int preview_values[6])
const auto& callback = [=](u16 val, std::string name, std::string pad_name, int preview_values[6])
{
SwitchPadInfo(pad_name, true);
if (!m_enable_buttons && !m_timer.isActive())
{
SwitchButtons(true);
}
if (m_handler->has_deadzones())
{
ui->preview_trigger_left->setValue(preview_values[0]);
@ -349,8 +356,18 @@ void pad_settings_dialog::InitButtons()
}
};
// Disable Button Remapping
const auto& fail_callback = [this](const std::string& pad_name)
{
SwitchPadInfo(pad_name, false);
if (m_enable_buttons)
{
SwitchButtons(false);
}
};
// Use timer to get button input
connect(&m_timer_input, &QTimer::timeout, [this, callback]()
connect(&m_timer_input, &QTimer::timeout, [this, callback, fail_callback]()
{
std::vector<std::string> buttons =
{
@ -359,8 +376,45 @@ void pad_settings_dialog::InitButtons()
m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key,
m_cfg_entries[button_ids::id_pad_rstick_up].key
};
m_handler->GetNextButtonPress(m_device_name, callback, false, buttons);
m_handler->GetNextButtonPress(m_device_name, callback, fail_callback, false, buttons);
});
// Use timer to refresh pad connection status
connect(&m_timer_pad_refresh, &QTimer::timeout, [this]()
{
for (int i = 0; i < ui->chooseDevice->count(); i++)
{
if (!ui->chooseDevice->itemData(i).canConvert<pad_info>())
{
LOG_FATAL(GENERAL, "Cannot convert itemData for index %d and itemText %s", i, sstr(ui->chooseDevice->itemText(i)));
continue;
}
const pad_info info = ui->chooseDevice->itemData(i).value<pad_info>();
m_handler->GetNextButtonPress(info.name, [=](u16 val, std::string name, std::string pad_name, int preview_values[6]) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false);
}
});
}
void pad_settings_dialog::SwitchPadInfo(const std::string& pad_name, bool is_connected)
{
for (int i = 0; i < ui->chooseDevice->count(); i++)
{
const pad_info info = ui->chooseDevice->itemData(i).value<pad_info>();
if (info.name == pad_name)
{
if (info.is_connected != is_connected)
{
ui->chooseDevice->setItemData(i, QVariant::fromValue(pad_info{ pad_name, is_connected }));
ui->chooseDevice->setItemText(i, is_connected ? qstr(pad_name) : (qstr(pad_name) + Disconnected_suffix));
}
if (!is_connected && m_timer.isActive() && ui->chooseDevice->currentIndex() == i)
{
ReactivateButtons();
}
break;
}
}
}
void pad_settings_dialog::ReloadButtons()
@ -406,9 +460,6 @@ void pad_settings_dialog::ReloadButtons()
updateButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right);
updateButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up);
// Enable Vibration Checkboxes
ui->gb_vibration->setEnabled(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);
@ -416,11 +467,11 @@ void pad_settings_dialog::ReloadButtons()
m_min_force = m_handler->vibration_min;
m_max_force = m_handler->vibration_max;
// Enable Deadzone Settings
const bool enable_deadzones = m_handler->has_deadzones();
// Enable Vibration Checkboxes
m_enable_rumble = m_handler->has_rumble();
ui->gb_sticks->setEnabled(enable_deadzones);
ui->gb_triggers->setEnabled(enable_deadzones);
// Enable Deadzone Settings
m_enable_deadzones = m_handler->has_deadzones();
// Enable Trigger Thresholds
ui->slider_trigger_left->setRange(0, m_handler->trigger_max);
@ -652,6 +703,12 @@ void pad_settings_dialog::UpdateLabel(bool is_reset)
void pad_settings_dialog::SwitchButtons(bool is_enabled)
{
m_enable_buttons = is_enabled;
ui->gb_vibration->setEnabled(is_enabled && m_enable_rumble);
ui->gb_sticks->setEnabled(is_enabled && m_enable_deadzones);
ui->gb_triggers->setEnabled(is_enabled && m_enable_deadzones);
for (int i = button_ids::id_pad_begin + 1; i < button_ids::id_pad_end; i++)
{
m_padButtons->button(i)->setEnabled(is_enabled);
@ -675,7 +732,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
UpdateLabel(true);
return;
case button_ids::id_blacklist:
m_handler->GetNextButtonPress(m_device_name, nullptr, true);
m_handler->GetNextButtonPress(m_device_name, nullptr, nullptr, true);
return;
default:
break;
@ -769,18 +826,20 @@ void pad_settings_dialog::ChangeInputType()
// Get this player's current handler and it's currently available devices
m_handler = GetHandler(g_cfg_input.player[player]->handler);
const std::vector<std::string> list_devices = m_handler->ListDevices();
const auto device_list = m_handler->ListDevices();
// Refill the device combobox with currently available devices
switch (m_handler->m_type)
{
#ifdef _WIN32
case pad_handler::ds4:
case pad_handler::xinput:
{
const QString name_string = qstr(m_handler->name_string());
for (int i = 0; i < m_handler->max_devices(); i++)
for (int i = 1; i <= m_handler->max_devices(); i++) // Controllers 1-n in GUI
{
ui->chooseDevice->addItem(name_string + QString::number(i), i);
const QString device_name = name_string + QString::number(i);
ui->chooseDevice->addItem(device_name, QVariant::fromValue(pad_info{ sstr(device_name), true }));
}
force_enable = true;
break;
@ -788,21 +847,34 @@ void pad_settings_dialog::ChangeInputType()
#endif
default:
{
for (int i = 0; i < list_devices.size(); i++)
for (int i = 0; i < device_list.size(); i++)
{
ui->chooseDevice->addItem(qstr(list_devices[i]), i);
ui->chooseDevice->addItem(qstr(device_list[i]), QVariant::fromValue(pad_info{ device_list[i], true }));
}
break;
}
}
// Handle empty device list
bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && list_devices.size() > 0);
bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && ui->chooseDevice->count() > 0);
ui->chooseDevice->setEnabled(config_enabled);
if (config_enabled)
{
ui->chooseDevice->setCurrentText(qstr(device));
for (int i = 0; i < ui->chooseDevice->count(); i++)
{
if (!ui->chooseDevice->itemData(i).canConvert<pad_info>())
{
LOG_FATAL(GENERAL, "Cannot convert itemData for index %d and itemText %s", i, sstr(ui->chooseDevice->itemText(i)));
continue;
}
const pad_info info = ui->chooseDevice->itemData(i).value<pad_info>();
m_handler->GetNextButtonPress(info.name, [=](u16 val, std::string name, std::string pad_name, int preview_values[6]) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false);
if (info.name == device)
{
ui->chooseDevice->setCurrentIndex(i);
}
}
QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type));
QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml");
@ -835,7 +907,7 @@ void pad_settings_dialog::ChangeInputType()
}
// enable configuration and profile list if possible
SwitchButtons(config_enabled);
SwitchButtons(config_enabled && m_handler->m_type == pad_handler::keyboard);
ui->b_addProfile->setEnabled(config_enabled);
ui->chooseProfile->setEnabled(config_enabled);
}
@ -856,6 +928,10 @@ void pad_settings_dialog::ChangeProfile()
{
m_timer_input.stop();
}
if (m_timer_pad_refresh.isActive())
{
m_timer_pad_refresh.stop();
}
// Change handler
const std::string cfg_name = PadHandlerBase::get_config_dir(m_handler->m_type) + m_profile + ".yml";
@ -900,6 +976,7 @@ void pad_settings_dialog::ChangeProfile()
if (ui->chooseDevice->isEnabled() && ui->chooseDevice->currentIndex() >= 0)
{
m_timer_input.start(1);
m_timer_pad_refresh.start(1000);
}
}
@ -944,16 +1021,6 @@ void pad_settings_dialog::SaveProfile()
m_handler_cfg.save();
}
void pad_settings_dialog::ResetPadHandler()
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads();
}
void pad_settings_dialog::SaveExit()
{
SaveProfile();
@ -970,8 +1037,6 @@ void pad_settings_dialog::SaveExit()
g_cfg_input.save();
ResetPadHandler();
QDialog::accept();
}

View file

@ -14,6 +14,14 @@ namespace Ui
class pad_settings_dialog;
}
struct pad_info
{
std::string name;
bool is_connected;
};
Q_DECLARE_METATYPE(pad_info);
class pad_settings_dialog : public QDialog
{
Q_OBJECT
@ -73,6 +81,8 @@ class pad_settings_dialog : public QDialog
QString text;
};
const QString Disconnected_suffix = tr(" (disconnected)");
public:
explicit pad_settings_dialog(QWidget *parent = nullptr);
~pad_settings_dialog();
@ -93,6 +103,11 @@ private:
// TabWidget
QTabWidget* m_tabs;
// Capabilities
bool m_enable_buttons{ false };
bool m_enable_rumble{ false };
bool m_enable_deadzones{ false };
// Button Mapping
QButtonGroup* m_padButtons;
u32 m_button_id = id_pad_begin;
@ -116,6 +131,7 @@ private:
pad_config m_handler_cfg;
std::string m_device_name;
std::string m_profile;
QTimer m_timer_pad_refresh;
// Remap Timer
const int MAX_SECONDS = 5;
@ -130,6 +146,7 @@ private:
/** Update all the Button Labels with current button mapping */
void UpdateLabel(bool is_reset = false);
void SwitchPadInfo(const std::string& name, bool is_connected);
/** Enable/Disable Buttons while trying to remap an other */
void SwitchButtons(bool is_enabled);
@ -141,7 +158,6 @@ private:
void ReloadButtons();
void ChangeProfile();
void ResetPadHandler();
/** Repaints a stick deadzone preview label */
void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y);

View file

@ -2,6 +2,9 @@
<ui version="4.0">
<class>pad_settings_dialog</class>
<widget class="QDialog" name="pad_settings_dialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>

View file

@ -784,6 +784,16 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> guiSettings, std:
xemu_settings->EnhanceCheckBox(ui->enableHostRoot, emu_settings::EnableHostRoot);
SubscribeTooltip(ui->enableHostRoot, json_sys["enableHostRoot"].toString());
xemu_settings->EnhanceCheckBox(ui->enableCacheClearing, emu_settings::LimitCacheSize);
SubscribeTooltip(ui->enableCacheClearing, json_sys["limitCacheSize"].toString());
connect(ui->enableCacheClearing, &QCheckBox::stateChanged, ui->maximumCacheSize, &QSlider::setEnabled);
// Sliders
EnhanceSlider(emu_settings::MaximumCacheSize, ui->maximumCacheSize, ui->maximumCacheSizeLabel, tr("Maximum size: %0 MB"));
SubscribeTooltip(ui->maximumCacheSize, json_sys["limitCacheSize"].toString());
ui->maximumCacheSize->setEnabled(ui->enableCacheClearing->isChecked());
// Radio Buttons
SubscribeTooltip(ui->gb_enterButtonAssignment, json_sys["enterButtonAssignment"].toString());

View file

@ -1149,6 +1149,55 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="1,1,1">
<item>
<widget class="QGroupBox" name="gb_DiskCacheClearing">
<property name="title">
<string>Disk cache</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_73">
<item>
<widget class="QCheckBox" name="enableCacheClearing">
<property name="text">
<string>Clear cache automatically</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="maximumCacheSizeLabel">
<property name="text">
<string>Cache size: 3072 MB</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="maximumCacheSize">
<property name="pageStep">
<number>512</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1024</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_14" native="true"/>
</item>
<item>
<widget class="QWidget" name="widget_15" native="true"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">

View file

@ -74,14 +74,14 @@ void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name)
cfg->from_default();
}
void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons)
void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{
if (get_blacklist)
blacklist.clear();
int device_number = GetDeviceNumber(padId);
if (device_number < 0)
return;
return fail_callback(padId);
DWORD dwResult;
XINPUT_STATE state;
@ -90,7 +90,7 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std:
// Simply get the state of the controller from XInput.
dwResult = (*xinputGetState)(static_cast<u32>(device_number), &state);
if (dwResult != ERROR_SUCCESS)
return;
return fail_callback(padId);
// Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed.
// Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold)
@ -131,9 +131,9 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std:
int preview_values[6] = { data[LT], data[RT], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] };
if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values);
return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else
return callback(0, "", preview_values);
return callback(0, "", padId, preview_values);
}
void xinput_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor)
@ -197,7 +197,7 @@ int xinput_pad_handler::GetDeviceNumber(const std::string& padId)
if (pos == std::string::npos)
return -1;
int device_number = std::stoul(padId.substr(pos + 12));
int device_number = std::stoul(padId.substr(pos + 12)) - 1; // Controllers 1-n in GUI
if (device_number >= XUSER_MAX_COUNT)
return -1;
@ -455,7 +455,7 @@ std::vector<std::string> xinput_pad_handler::ListDevices()
XINPUT_STATE state;
DWORD result = (*xinputGetState)(i, &state);
if (result == ERROR_SUCCESS)
xinput_pads_list.push_back(m_name_string + std::to_string(i));
xinput_pads_list.push_back(m_name_string + std::to_string(i + 1)); // Controllers 1-n in GUI
}
return xinput_pads_list;
}

View file

@ -107,7 +107,7 @@ public:
std::vector<std::string> ListDevices() override;
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 GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_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;