Merge branch 'master' into Update-SDL

This commit is contained in:
Megamouse 2025-05-15 14:56:00 +02:00 committed by GitHub
commit 73fd2040d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 332 additions and 409 deletions

@ -1 +1 @@
Subproject commit 5ac37a8ffcf89da390404c1016833d56e2d67ae4 Subproject commit 8d604353a53853fa56d1bdce0363535605ca868f

View file

@ -107,13 +107,8 @@ struct cross_controller
void stop_thread() void stop_thread()
{ {
if (connection_thread) // Join thread
{ connection_thread.reset();
auto& thread = *connection_thread;
thread = thread_state::aborting;
thread();
connection_thread.reset();
}
}; };
}; };

View file

@ -828,13 +828,8 @@ void rec_info::stop_video_provider(bool flush)
{ {
cellRec.notice("Stopping video provider."); cellRec.notice("Stopping video provider.");
if (video_provider_thread) // Join thread
{ video_provider_thread.reset();
auto& thread = *video_provider_thread;
thread = thread_state::aborting;
thread();
video_provider_thread.reset();
}
// Flush the ringbuffer if necessary. // Flush the ringbuffer if necessary.
// This should only happen if the video sink is not the encoder itself. // This should only happen if the video sink is not the encoder itself.

View file

@ -59,13 +59,7 @@ struct sce_np_util_manager
void join_thread() void join_thread()
{ {
if (bandwidth_test_thread) bandwidth_test_thread.reset();
{
auto& thread = *bandwidth_test_thread;
thread = thread_state::aborting;
thread();
bandwidth_test_thread.reset();
}
} }
}; };

View file

@ -4781,6 +4781,26 @@ bool spu_thread::process_mfc_cmd()
return true; return true;
} }
if (last_getllar != pc || last_getllar_lsa != ch_mfc_cmd.lsa)
{
getllar_busy_waiting_switch = umax;
getllar_spin_count = 0;
return true;
}
// Check if LSA points to an OUT buffer on the stack from a caller - unlikely to be a loop
if (last_getllar_lsa >= SPU_LS_SIZE - 0x10000 && last_getllar_lsa > last_getllar_gpr1)
{
auto cs = dump_callstack_list();
if (!cs.empty() && last_getllar_lsa > cs[0].second)
{
getllar_busy_waiting_switch = umax;
getllar_spin_count = 0;
return true;
}
}
getllar_spin_count = std::min<u32>(getllar_spin_count + 1, u16{umax}); getllar_spin_count = std::min<u32>(getllar_spin_count + 1, u16{umax});
if (getllar_busy_waiting_switch == umax && getllar_spin_count == 4) if (getllar_busy_waiting_switch == umax && getllar_spin_count == 4)
@ -4826,6 +4846,7 @@ bool spu_thread::process_mfc_cmd()
last_getllar = pc; last_getllar = pc;
last_getllar_gpr1 = gpr[1]._u32[3]; last_getllar_gpr1 = gpr[1]._u32[3];
last_getllar_lsa = ch_mfc_cmd.lsa;
if (getllar_busy_waiting_switch == 1) if (getllar_busy_waiting_switch == 1)
{ {

View file

@ -802,6 +802,7 @@ public:
u32 last_getllar = umax; // LS address of last GETLLAR (if matches current GETLLAR we can let the thread rest) u32 last_getllar = umax; // LS address of last GETLLAR (if matches current GETLLAR we can let the thread rest)
u32 last_getllar_gpr1 = umax; u32 last_getllar_gpr1 = umax;
u32 last_getllar_addr = umax; u32 last_getllar_addr = umax;
u32 last_getllar_lsa = umax;
u32 getllar_spin_count = 0; u32 getllar_spin_count = 0;
u32 getllar_busy_waiting_switch = umax; // umax means the test needs evaluation, otherwise it's a boolean u32 getllar_busy_waiting_switch = umax; // umax means the test needs evaluation, otherwise it's a boolean
u64 getllar_evaluate_time = 0; u64 getllar_evaluate_time = 0;

View file

@ -58,12 +58,12 @@ usb_device_logitech_g27::usb_device_logitech_g27(u32 controller_index, const std
if (!m_enabled) if (!m_enabled)
return; return;
m_house_keeping_thread = std::thread([this]() m_house_keeping_thread = std::make_unique<named_thread<std::function<void()>>>("Logitech G27", [this]()
{ {
while (!m_stop_thread) while (thread_ctrl::state() != thread_state::aborting)
{ {
sdl_refresh(); sdl_refresh();
std::this_thread::sleep_for(std::chrono::seconds(5)); thread_ctrl::wait_for(5'000'000);
} }
}); });
} }
@ -73,7 +73,7 @@ bool usb_device_logitech_g27::open_device()
return m_enabled; return m_enabled;
} }
static void clear_sdl_joysticks(std::map<u32, std::vector<SDL_Joystick*>>& joystick_map) static void clear_sdl_joysticks(std::map<u64, std::vector<SDL_Joystick*>>& joystick_map)
{ {
for (auto& [type, joysticks] : joystick_map) for (auto& [type, joysticks] : joystick_map)
{ {
@ -88,12 +88,8 @@ static void clear_sdl_joysticks(std::map<u32, std::vector<SDL_Joystick*>>& joyst
usb_device_logitech_g27::~usb_device_logitech_g27() usb_device_logitech_g27::~usb_device_logitech_g27()
{ {
// stop the house keeping thread // Wait for the house keeping thread to finish
m_stop_thread = true; m_house_keeping_thread.reset();
// wait for the house keeping thread to finish
if (m_house_keeping_thread.joinable())
m_house_keeping_thread.join();
// Close sdl handles // Close sdl handles
{ {
@ -128,7 +124,7 @@ void usb_device_logitech_g27::control_transfer(u8 bmRequestType, u8 bRequest, u1
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
} }
static bool sdl_joysticks_equal(std::map<u32, std::vector<SDL_Joystick*>>& left, std::map<u32, std::vector<SDL_Joystick*>>& right) static bool sdl_joysticks_equal(std::map<u64, std::vector<SDL_Joystick*>>& left, std::map<u64, std::vector<SDL_Joystick*>>& right)
{ {
if (left.size() != right.size()) if (left.size() != right.size())
{ {
@ -225,17 +221,14 @@ void usb_device_logitech_g27::sdl_refresh()
m_reverse_effects = g_cfg_logitech_g27.reverse_effects.get(); m_reverse_effects = g_cfg_logitech_g27.reverse_effects.get();
const u32 ffb_vendor_id = g_cfg_logitech_g27.ffb_device_type_id.get() >> 16; const u64 ffb_device_type_id = g_cfg_logitech_g27.ffb_device_type_id.get();
const u32 ffb_product_id = g_cfg_logitech_g27.ffb_device_type_id.get() & 0xFFFF; const u64 led_device_type_id = g_cfg_logitech_g27.led_device_type_id.get();
const u32 led_vendor_id = g_cfg_logitech_g27.led_device_type_id.get() >> 16;
const u32 led_product_id = g_cfg_logitech_g27.led_device_type_id.get() & 0xFFFF;
lock.unlock(); lock.unlock();
SDL_Joystick* new_led_joystick_handle = nullptr; SDL_Joystick* new_led_joystick_handle = nullptr;
SDL_Haptic* new_haptic_handle = nullptr; SDL_Haptic* new_haptic_handle = nullptr;
std::map<u32, std::vector<SDL_Joystick*>> new_joysticks; std::map<u64, std::vector<SDL_Joystick*>> new_joysticks;
int joystick_count = 0; int joystick_count = 0;
if (SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&joystick_count)) if (SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&joystick_count))
@ -250,7 +243,15 @@ void usb_device_logitech_g27::sdl_refresh()
} }
const u16 cur_vendor_id = SDL_GetJoystickVendor(cur_joystick); const u16 cur_vendor_id = SDL_GetJoystickVendor(cur_joystick);
const u16 cur_product_id = SDL_GetJoystickProduct(cur_joystick); const u16 cur_product_id = SDL_GetJoystickProduct(cur_joystick);
const u32 joystick_type_id = (cur_vendor_id << 16) | cur_product_id; const emulated_g27_device_type_id joystick_type_id_struct =
{
.product_id = static_cast<u64>(cur_product_id),
.vendor_id = static_cast<u64>(cur_vendor_id),
.num_axes = static_cast<u64>(SDL_GetNumJoystickAxes(cur_joystick)),
.num_hats = static_cast<u64>(SDL_GetNumJoystickHats(cur_joystick)),
.num_buttons = static_cast<u64>(SDL_GetNumJoystickButtons(cur_joystick))
};
const u64 joystick_type_id = joystick_type_id_struct.as_u64();
auto joysticks_of_type = new_joysticks.find(joystick_type_id); auto joysticks_of_type = new_joysticks.find(joystick_type_id);
if (joysticks_of_type == new_joysticks.end()) if (joysticks_of_type == new_joysticks.end())
{ {
@ -261,7 +262,7 @@ void usb_device_logitech_g27::sdl_refresh()
joysticks_of_type->second.push_back(cur_joystick); joysticks_of_type->second.push_back(cur_joystick);
} }
if (cur_vendor_id == ffb_vendor_id && cur_product_id == ffb_product_id && new_haptic_handle == nullptr) if (joystick_type_id == ffb_device_type_id && new_haptic_handle == nullptr)
{ {
SDL_Haptic* cur_haptic = SDL_OpenHapticFromJoystick(cur_joystick); SDL_Haptic* cur_haptic = SDL_OpenHapticFromJoystick(cur_joystick);
if (cur_haptic == nullptr) if (cur_haptic == nullptr)
@ -274,7 +275,7 @@ void usb_device_logitech_g27::sdl_refresh()
} }
} }
if (cur_vendor_id == led_vendor_id && cur_product_id == led_product_id && new_led_joystick_handle == nullptr) if (joystick_type_id == led_device_type_id && new_led_joystick_handle == nullptr)
{ {
new_led_joystick_handle = cur_joystick; new_led_joystick_handle = cur_joystick;
} }
@ -576,7 +577,7 @@ static s16 fetch_sdl_as_axis(SDL_Joystick* joystick, const sdl_mapping& mapping)
return 0; return 0;
} }
static s16 fetch_sdl_axis_avg(std::map<u32, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping) static s16 fetch_sdl_axis_avg(std::map<u64, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping)
{ {
constexpr s16 MAX = 0x7FFF; constexpr s16 MAX = 0x7FFF;
constexpr s16 MIN = -0x8000; constexpr s16 MIN = -0x8000;
@ -602,7 +603,7 @@ static s16 fetch_sdl_axis_avg(std::map<u32, std::vector<SDL_Joystick*>>& joystic
return std::clamp<s16>(sdl_joysticks_total_value / static_cast<s32>(joysticks_of_type->second.size()), MIN, MAX); return std::clamp<s16>(sdl_joysticks_total_value / static_cast<s32>(joysticks_of_type->second.size()), MIN, MAX);
} }
static bool sdl_to_logitech_g27_button(std::map<u32, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping) static bool sdl_to_logitech_g27_button(std::map<u64, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping)
{ {
auto joysticks_of_type = joysticks.find(mapping.device_type_id); auto joysticks_of_type = joysticks.find(mapping.device_type_id);
if (joysticks_of_type == joysticks.end()) if (joysticks_of_type == joysticks.end())
@ -623,14 +624,14 @@ static bool sdl_to_logitech_g27_button(std::map<u32, std::vector<SDL_Joystick*>>
return pressed; return pressed;
} }
static u16 sdl_to_logitech_g27_steering(std::map<u32, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping) static u16 sdl_to_logitech_g27_steering(std::map<u64, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping)
{ {
const s16 avg = fetch_sdl_axis_avg(joysticks, mapping); const s16 avg = fetch_sdl_axis_avg(joysticks, mapping);
const u16 unsigned_avg = avg + 0x8000; const u16 unsigned_avg = avg + 0x8000;
return unsigned_avg * (0xFFFF >> 2) / 0xFFFF; return unsigned_avg * (0xFFFF >> 2) / 0xFFFF;
} }
static u8 sdl_to_logitech_g27_pedal(std::map<u32, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping) static u8 sdl_to_logitech_g27_pedal(std::map<u64, std::vector<SDL_Joystick*>>& joysticks, const sdl_mapping& mapping)
{ {
const s16 avg = fetch_sdl_axis_avg(joysticks, mapping); const s16 avg = fetch_sdl_axis_avg(joysticks, mapping);
const u16 unsigned_avg = avg + 0x8000; const u16 unsigned_avg = avg + 0x8000;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Emu/Io/usb_device.h" #include "Emu/Io/usb_device.h"
#include "Utilities/Thread.h"
#include "LogitechG27Config.h" #include "LogitechG27Config.h"
#ifndef _MSC_VER #ifndef _MSC_VER
@ -14,7 +15,6 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <thread>
enum class logitech_g27_ffb_state enum class logitech_g27_ffb_state
{ {
@ -36,7 +36,16 @@ struct logitech_g27_ffb_slot
struct sdl_mapping struct sdl_mapping
{ {
u32 device_type_id = 0; // (vendor_id << 16) | product_id /*
* orginally 32bit, just vendor product match
* v1: (vendor_id << 16) | product_id
*
* now 64bit, matching more to handle Fanatec's shenanigans, should be good until Fanatec desides that it's funny to register > 1023 axes/hats/buttons, then have two hid devices with the exact same numbers with one single wheel base
* serial/version/firmware/guid is not used for now because those are still unreliable in SDL in the context of config
* not migrating to string yet, don't want to make joystick look up heavy
* v2: (num_buttons:10 << 52) | (num_hats:10 << 42) | (num_axes:10 << 32) | (vendor_id:16 << 16) | product_id:16
*/
u64 device_type_id = 0;
sdl_mapping_type type = sdl_mapping_type::button; sdl_mapping_type type = sdl_mapping_type::button;
u64 id = 0; u64 id = 0;
hat_component hat = hat_component::none; hat_component hat = hat_component::none;
@ -111,7 +120,7 @@ private:
std::mutex m_sdl_handles_mutex; std::mutex m_sdl_handles_mutex;
SDL_Joystick* m_led_joystick_handle = nullptr; SDL_Joystick* m_led_joystick_handle = nullptr;
SDL_Haptic* m_haptic_handle = nullptr; SDL_Haptic* m_haptic_handle = nullptr;
std::map<u32, std::vector<SDL_Joystick*>> m_joysticks; std::map<u64, std::vector<SDL_Joystick*>> m_joysticks;
bool m_fixed_loop = false; bool m_fixed_loop = false;
u16 m_wheel_range = 200; u16 m_wheel_range = 200;
std::array<logitech_g27_ffb_slot, 4> m_effect_slots {}; std::array<logitech_g27_ffb_slot, 4> m_effect_slots {};
@ -122,6 +131,5 @@ private:
bool m_enabled = false; bool m_enabled = false;
std::thread m_house_keeping_thread; std::unique_ptr<named_thread<std::function<void()>>> m_house_keeping_thread;
atomic_t<bool> m_stop_thread { false };
}; };

View file

@ -20,15 +20,37 @@ enum class hat_component
right right
}; };
// this was a bitfield, but juggling at least 3 compilers and OSes means no bitfield
// num_buttons:10 << 52 | num_hats:10 << 42 | num_axes:10 << 32 | vendor_id:16 << 16 | product_id:16
struct emulated_g27_device_type_id
{
// big types to keep 64bit bit shift operations sane
u64 product_id = 0;
u64 vendor_id = 0;
u64 num_axes = 0;
u64 num_hats = 0;
u64 num_buttons = 0;
u64 as_u64() const
{
u64 value = product_id;
value |= vendor_id << 16;
value |= (num_axes & ((1 << 10) - 1)) << 32;
value |= (num_hats & ((1 << 10) - 1)) << 42;
value |= (num_buttons & ((1 << 10) - 1)) << 52;
return value;
}
};
struct emulated_logitech_g27_mapping : cfg::node struct emulated_logitech_g27_mapping : cfg::node
{ {
cfg::uint<0, 0xFFFFFFFF> device_type_id; cfg::uint<0, 0xFFFFFFFFFFFFFFFF> device_type_id;
cfg::_enum<sdl_mapping_type> type; cfg::_enum<sdl_mapping_type> type;
cfg::uint<0, 0xFFFFFFFFFFFFFFFF> id; cfg::uint<0, 0xFFFFFFFFFFFFFFFF> id;
cfg::_enum<hat_component> hat; cfg::_enum<hat_component> hat;
cfg::_bool reverse; cfg::_bool reverse;
emulated_logitech_g27_mapping(cfg::node* owner, std::string name, u32 device_type_id_def, sdl_mapping_type type_def, uint64_t id_def, hat_component hat_def, bool reverse_def) emulated_logitech_g27_mapping(cfg::node* owner, std::string name, u64 device_type_id_def, sdl_mapping_type type_def, u64 id_def, hat_component hat_def, bool reverse_def)
: cfg::node(owner, std::move(name)), : cfg::node(owner, std::move(name)),
device_type_id(this, "device_type_id", device_type_id_def), device_type_id(this, "device_type_id", device_type_id_def),
type(this, "type", type_def), type(this, "type", type_def),
@ -45,49 +67,50 @@ public:
std::mutex m_mutex; std::mutex m_mutex;
// TODO these defaults are for a shifter-less G29 + a xbox controller for shifter testing, perhaps find a new default // TODO these defaults are for a shifter-less G29 + a xbox controller for shifter testing, perhaps find a new default
// TODO, when a new default is found, use the new device type id style
emulated_logitech_g27_mapping steering{this, "steering", 0x046dc24f, sdl_mapping_type::axis, 0, hat_component::none, false}; emulated_logitech_g27_mapping steering{this, "steering", 0, sdl_mapping_type::axis, 0, hat_component::none, false};
emulated_logitech_g27_mapping throttle{this, "throttle", 0x046dc24f, sdl_mapping_type::axis, 2, hat_component::none, false}; emulated_logitech_g27_mapping throttle{this, "throttle", 0, sdl_mapping_type::axis, 2, hat_component::none, false};
emulated_logitech_g27_mapping brake{this, "brake", 0x046dc24f, sdl_mapping_type::axis, 3, hat_component::none, false}; emulated_logitech_g27_mapping brake{this, "brake", 0, sdl_mapping_type::axis, 3, hat_component::none, false};
emulated_logitech_g27_mapping clutch{this, "clutch", 0x046dc24f, sdl_mapping_type::axis, 1, hat_component::none, false}; emulated_logitech_g27_mapping clutch{this, "clutch", 0, sdl_mapping_type::axis, 1, hat_component::none, false};
emulated_logitech_g27_mapping shift_up{this, "shift_up", 0x046dc24f, sdl_mapping_type::button, 4, hat_component::none, false}; emulated_logitech_g27_mapping shift_up{this, "shift_up", 0, sdl_mapping_type::button, 4, hat_component::none, false};
emulated_logitech_g27_mapping shift_down{this, "shift_down", 0x046dc24f, sdl_mapping_type::button, 5, hat_component::none, false}; emulated_logitech_g27_mapping shift_down{this, "shift_down", 0, sdl_mapping_type::button, 5, hat_component::none, false};
emulated_logitech_g27_mapping up{this, "up", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::up, false}; emulated_logitech_g27_mapping up{this, "up", 0, sdl_mapping_type::hat, 0, hat_component::up, false};
emulated_logitech_g27_mapping down{this, "down", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::down, false}; emulated_logitech_g27_mapping down{this, "down", 0, sdl_mapping_type::hat, 0, hat_component::down, false};
emulated_logitech_g27_mapping left{this, "left", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::left, false}; emulated_logitech_g27_mapping left{this, "left", 0, sdl_mapping_type::hat, 0, hat_component::left, false};
emulated_logitech_g27_mapping right{this, "right", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::right, false}; emulated_logitech_g27_mapping right{this, "right", 0, sdl_mapping_type::hat, 0, hat_component::right, false};
emulated_logitech_g27_mapping triangle{this, "triangle", 0x046dc24f, sdl_mapping_type::button, 3, hat_component::none, false}; emulated_logitech_g27_mapping triangle{this, "triangle", 0, sdl_mapping_type::button, 3, hat_component::none, false};
emulated_logitech_g27_mapping cross{this, "cross", 0x046dc24f, sdl_mapping_type::button, 0, hat_component::none, false}; emulated_logitech_g27_mapping cross{this, "cross", 0, sdl_mapping_type::button, 0, hat_component::none, false};
emulated_logitech_g27_mapping square{this, "square", 0x046dc24f, sdl_mapping_type::button, 1, hat_component::none, false}; emulated_logitech_g27_mapping square{this, "square", 0, sdl_mapping_type::button, 1, hat_component::none, false};
emulated_logitech_g27_mapping circle{this, "circle", 0x046dc24f, sdl_mapping_type::button, 2, hat_component::none, false}; emulated_logitech_g27_mapping circle{this, "circle", 0, sdl_mapping_type::button, 2, hat_component::none, false};
emulated_logitech_g27_mapping l2{this, "l2", 0x046dc24f, sdl_mapping_type::button, 7, hat_component::none, false}; emulated_logitech_g27_mapping l2{this, "l2", 0, sdl_mapping_type::button, 7, hat_component::none, false};
emulated_logitech_g27_mapping l3{this, "l3", 0x046dc24f, sdl_mapping_type::button, 11, hat_component::none, false}; emulated_logitech_g27_mapping l3{this, "l3", 0, sdl_mapping_type::button, 11, hat_component::none, false};
emulated_logitech_g27_mapping r2{this, "r2", 0x046dc24f, sdl_mapping_type::button, 6, hat_component::none, false}; emulated_logitech_g27_mapping r2{this, "r2", 0, sdl_mapping_type::button, 6, hat_component::none, false};
emulated_logitech_g27_mapping r3{this, "r3", 0x046dc24f, sdl_mapping_type::button, 10, hat_component::none, false}; emulated_logitech_g27_mapping r3{this, "r3", 0, sdl_mapping_type::button, 10, hat_component::none, false};
emulated_logitech_g27_mapping plus{this, "plus", 0x046dc24f, sdl_mapping_type::button, 19, hat_component::none, false}; emulated_logitech_g27_mapping plus{this, "plus", 0, sdl_mapping_type::button, 19, hat_component::none, false};
emulated_logitech_g27_mapping minus{this, "minus", 0x046dc24f, sdl_mapping_type::button, 20, hat_component::none, false}; emulated_logitech_g27_mapping minus{this, "minus", 0, sdl_mapping_type::button, 20, hat_component::none, false};
emulated_logitech_g27_mapping dial_clockwise{this, "dial_clockwise", 0x046dc24f, sdl_mapping_type::button, 21, hat_component::none, false}; emulated_logitech_g27_mapping dial_clockwise{this, "dial_clockwise", 0, sdl_mapping_type::button, 21, hat_component::none, false};
emulated_logitech_g27_mapping dial_anticlockwise{this, "dial_anticlockwise", 0x046dc24f, sdl_mapping_type::button, 22, hat_component::none, false}; emulated_logitech_g27_mapping dial_anticlockwise{this, "dial_anticlockwise", 0, sdl_mapping_type::button, 22, hat_component::none, false};
emulated_logitech_g27_mapping select{this, "select", 0x046dc24f, sdl_mapping_type::button, 8, hat_component::none, false}; emulated_logitech_g27_mapping select{this, "select", 0, sdl_mapping_type::button, 8, hat_component::none, false};
emulated_logitech_g27_mapping pause{this, "pause", 0x046dc24f, sdl_mapping_type::button, 9, hat_component::none, false}; emulated_logitech_g27_mapping pause{this, "pause", 0, sdl_mapping_type::button, 9, hat_component::none, false};
emulated_logitech_g27_mapping shifter_1{this, "shifter_1", 0x045e028e, sdl_mapping_type::button, 3, hat_component::none, false}; emulated_logitech_g27_mapping shifter_1{this, "shifter_1", 0, sdl_mapping_type::button, 3, hat_component::none, false};
emulated_logitech_g27_mapping shifter_2{this, "shifter_2", 0x045e028e, sdl_mapping_type::button, 0, hat_component::none, false}; emulated_logitech_g27_mapping shifter_2{this, "shifter_2", 0, sdl_mapping_type::button, 0, hat_component::none, false};
emulated_logitech_g27_mapping shifter_3{this, "shifter_3", 0x045e028e, sdl_mapping_type::button, 2, hat_component::none, false}; emulated_logitech_g27_mapping shifter_3{this, "shifter_3", 0, sdl_mapping_type::button, 2, hat_component::none, false};
emulated_logitech_g27_mapping shifter_4{this, "shifter_4", 0x045e028e, sdl_mapping_type::button, 1, hat_component::none, false}; emulated_logitech_g27_mapping shifter_4{this, "shifter_4", 0, sdl_mapping_type::button, 1, hat_component::none, false};
emulated_logitech_g27_mapping shifter_5{this, "shifter_5", 0x045e028e, sdl_mapping_type::hat, 0, hat_component::up, false}; emulated_logitech_g27_mapping shifter_5{this, "shifter_5", 0, sdl_mapping_type::hat, 0, hat_component::up, false};
emulated_logitech_g27_mapping shifter_6{this, "shifter_6", 0x045e028e, sdl_mapping_type::hat, 0, hat_component::down, false}; emulated_logitech_g27_mapping shifter_6{this, "shifter_6", 0, sdl_mapping_type::hat, 0, hat_component::down, false};
emulated_logitech_g27_mapping shifter_r{this, "shifter_r", 0x045e028e, sdl_mapping_type::hat, 0, hat_component::left, false}; emulated_logitech_g27_mapping shifter_r{this, "shifter_r", 0, sdl_mapping_type::hat, 0, hat_component::left, false};
cfg::_bool reverse_effects{this, "reverse_effects", true}; cfg::_bool reverse_effects{this, "reverse_effects", false};
cfg::uint<0, 0xFFFFFFFF> ffb_device_type_id{this, "ffb_device_type_id", 0x046dc24f}; cfg::uint<0, 0xFFFFFFFFFFFFFFFF> ffb_device_type_id{this, "ffb_device_type_id", 0};
cfg::uint<0, 0xFFFFFFFF> led_device_type_id{this, "led_device_type_id", 0x046dc24f}; cfg::uint<0, 0xFFFFFFFFFFFFFFFF> led_device_type_id{this, "led_device_type_id", 0};
cfg::_bool enabled{this, "enabled", false}; cfg::_bool enabled{this, "enabled", false};

View file

@ -47,13 +47,8 @@ gui_pad_thread::gui_pad_thread()
gui_pad_thread::~gui_pad_thread() gui_pad_thread::~gui_pad_thread()
{ {
if (m_thread) // Join thread
{ m_thread.reset();
auto& thread = *m_thread;
thread = thread_state::aborting;
thread();
m_thread.reset();
}
#ifdef __linux__ #ifdef __linux__
if (m_uinput_fd != 1) if (m_uinput_fd != 1)

View file

@ -101,12 +101,8 @@ hid_pad_handler<Device>::hid_pad_handler(pad_handler type, std::vector<id_pair>
template <class Device> template <class Device>
hid_pad_handler<Device>::~hid_pad_handler() hid_pad_handler<Device>::~hid_pad_handler()
{ {
if (m_enumeration_thread) // Join thread
{ m_enumeration_thread.reset();
auto& enumeration_thread = *m_enumeration_thread;
enumeration_thread = thread_state::aborting;
enumeration_thread();
}
for (auto& controller : m_controllers) for (auto& controller : m_controllers)
{ {

View file

@ -309,13 +309,10 @@ void pad_thread::operator()()
for (auto& thread : threads) for (auto& thread : threads)
{ {
if (thread) // Join thread (ordered explicitly)
{ thread.reset();
auto& enumeration_thread = *thread;
enumeration_thread = thread_state::aborting;
enumeration_thread();
}
} }
threads.clear(); threads.clear();
input_log.notice("Pad threads stopped"); input_log.notice("Pad threads stopped");

View file

@ -277,13 +277,8 @@ void raw_mouse::update_values(s32 scan_code, bool pressed)
raw_mouse_handler::~raw_mouse_handler() raw_mouse_handler::~raw_mouse_handler()
{ {
if (m_thread) // Join thread
{ m_thread.reset();
auto& thread = *m_thread;
thread = thread_state::aborting;
thread();
m_thread.reset();
}
#ifdef _WIN32 #ifdef _WIN32
unregister_raw_input_devices(); unregister_raw_input_devices();

View file

@ -5,6 +5,7 @@
#include "emulated_logitech_g27_settings_dialog.h" #include "emulated_logitech_g27_settings_dialog.h"
#include "Emu/Io/LogitechG27.h" #include "Emu/Io/LogitechG27.h"
#include "Input/sdl_instance.h" #include "Input/sdl_instance.h"
#include "qt_utils.h"
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QGroupBox> #include <QGroupBox>
@ -21,14 +22,19 @@ LOG_CHANNEL(logitech_g27_cfg_log, "LOGIG27");
static const QString DEFAULT_STATUS = " "; static const QString DEFAULT_STATUS = " ";
enum class mapping_device_choice enum class mapping_device
{ {
NONE = -1, NONE = -1,
// Axis
STEERING = 0, STEERING = 0,
THROTTLE, THROTTLE,
BRAKE, BRAKE,
CLUTCH, CLUTCH,
SHIFT_UP,
// Buttons
FIRST_BUTTON,
SHIFT_UP = FIRST_BUTTON,
SHIFT_DOWN, SHIFT_DOWN,
UP, UP,
@ -61,9 +67,94 @@ enum class mapping_device_choice
SHIFTER_4, SHIFTER_4,
SHIFTER_5, SHIFTER_5,
SHIFTER_6, SHIFTER_6,
SHIFTER_R SHIFTER_R,
// Enum count
COUNT
}; };
QString device_name(mapping_device dev)
{
switch (dev)
{
case mapping_device::NONE: return "";
case mapping_device::STEERING: return QObject::tr("Steering");
case mapping_device::THROTTLE: return QObject::tr("Throttle");
case mapping_device::BRAKE: return QObject::tr("Brake");
case mapping_device::CLUTCH: return QObject::tr("Clutch");
case mapping_device::SHIFT_UP: return QObject::tr("Shift up");
case mapping_device::SHIFT_DOWN: return QObject::tr("Shift down");
case mapping_device::UP: return QObject::tr("Up");
case mapping_device::DOWN: return QObject::tr("Down");
case mapping_device::LEFT: return QObject::tr("Left");
case mapping_device::RIGHT: return QObject::tr("Right");
case mapping_device::TRIANGLE: return QObject::tr("Triangle");
case mapping_device::CROSS: return QObject::tr("Cross");
case mapping_device::SQUARE: return QObject::tr("Square");
case mapping_device::CIRCLE: return QObject::tr("Circle");
case mapping_device::L2: return QObject::tr("L2");
case mapping_device::L3: return QObject::tr("L3");
case mapping_device::R2: return QObject::tr("R2");
case mapping_device::R3: return QObject::tr("R3");
case mapping_device::PLUS: return QObject::tr("L4");
case mapping_device::MINUS: return QObject::tr("L5");
case mapping_device::DIAL_CLOCKWISE: return QObject::tr("R4");
case mapping_device::DIAL_ANTICLOCKWISE: return QObject::tr("R5");
case mapping_device::SELECT: return QObject::tr("Select");
case mapping_device::PAUSE: return QObject::tr("Pause");
case mapping_device::SHIFTER_1: return QObject::tr("Gear 1");
case mapping_device::SHIFTER_2: return QObject::tr("Gear 2");
case mapping_device::SHIFTER_3: return QObject::tr("Gear 3");
case mapping_device::SHIFTER_4: return QObject::tr("Gear 4");
case mapping_device::SHIFTER_5: return QObject::tr("Gear 5");
case mapping_device::SHIFTER_6: return QObject::tr("Gear 6");
case mapping_device::SHIFTER_R: return QObject::tr("Gear R");
case mapping_device::COUNT: return "";
}
return "";
}
emulated_logitech_g27_mapping& device_cfg(mapping_device dev)
{
auto& cfg = g_cfg_logitech_g27;
switch (dev)
{
case mapping_device::STEERING: return cfg.steering;
case mapping_device::THROTTLE: return cfg.throttle;
case mapping_device::BRAKE: return cfg.brake;
case mapping_device::CLUTCH: return cfg.clutch;
case mapping_device::SHIFT_UP: return cfg.shift_up;
case mapping_device::SHIFT_DOWN: return cfg.shift_down;
case mapping_device::UP: return cfg.up;
case mapping_device::DOWN: return cfg.down;
case mapping_device::LEFT: return cfg.left;
case mapping_device::RIGHT: return cfg.right;
case mapping_device::TRIANGLE: return cfg.triangle;
case mapping_device::CROSS: return cfg.cross;
case mapping_device::SQUARE: return cfg.square;
case mapping_device::CIRCLE: return cfg.circle;
case mapping_device::L2: return cfg.l2;
case mapping_device::L3: return cfg.l3;
case mapping_device::R2: return cfg.r2;
case mapping_device::R3: return cfg.r3;
case mapping_device::PLUS: return cfg.plus;
case mapping_device::MINUS: return cfg.minus;
case mapping_device::DIAL_CLOCKWISE: return cfg.dial_clockwise;
case mapping_device::DIAL_ANTICLOCKWISE: return cfg.dial_anticlockwise;
case mapping_device::SELECT: return cfg.select;
case mapping_device::PAUSE: return cfg.pause;
case mapping_device::SHIFTER_1: return cfg.shifter_1;
case mapping_device::SHIFTER_2: return cfg.shifter_2;
case mapping_device::SHIFTER_3: return cfg.shifter_3;
case mapping_device::SHIFTER_4: return cfg.shifter_4;
case mapping_device::SHIFTER_5: return cfg.shifter_5;
case mapping_device::SHIFTER_6: return cfg.shifter_6;
case mapping_device::SHIFTER_R: return cfg.shifter_r;
default: fmt::throw_exception("Unexpected mapping_device %d", static_cast<int>(dev));
}
}
class DeviceChoice : public QWidget class DeviceChoice : public QWidget
{ {
public: public:
@ -91,66 +182,33 @@ public:
const QVariant var = m_dropdown->currentData(); const QVariant var = m_dropdown->currentData();
if (!var.canConvert<int>()) return; if (!var.canConvert<int>()) return;
m_device_choice = static_cast<mapping_device_choice>(var.toInt()); m_device_choice = static_cast<mapping_device>(var.toInt());
update_display(); update_display();
}); });
connect(m_disable_button, &QPushButton::clicked, this, [this]() connect(m_disable_button, &QPushButton::clicked, this, [this]()
{ {
m_device_choice = mapping_device_choice::NONE; m_device_choice = mapping_device::NONE;
update_display(); update_display();
}); });
m_dropdown->setPlaceholderText(tr("-- Disabled --")); m_dropdown->setPlaceholderText(tr("-- Disabled --"));
m_dropdown->addItem(tr("Steering"), static_cast<int>(mapping_device_choice::STEERING)); for (int i = 0; i < static_cast<int>(mapping_device::COUNT); i++)
m_dropdown->addItem(tr("Throttle"), static_cast<int>(mapping_device_choice::THROTTLE)); {
m_dropdown->addItem(tr("Brake"), static_cast<int>(mapping_device_choice::BRAKE)); const mapping_device dev = static_cast<mapping_device>(i);
m_dropdown->addItem(tr("Clutch"), static_cast<int>(mapping_device_choice::CLUTCH)); m_dropdown->addItem(device_name(dev), i);
m_dropdown->addItem(tr("Shift up"), static_cast<int>(mapping_device_choice::SHIFT_UP)); }
m_dropdown->addItem(tr("Shift down"), static_cast<int>(mapping_device_choice::SHIFT_DOWN));
m_dropdown->addItem(tr("Up"), static_cast<int>(mapping_device_choice::UP));
m_dropdown->addItem(tr("Down"), static_cast<int>(mapping_device_choice::DOWN));
m_dropdown->addItem(tr("Left"), static_cast<int>(mapping_device_choice::LEFT));
m_dropdown->addItem(tr("Right"), static_cast<int>(mapping_device_choice::RIGHT));
m_dropdown->addItem(tr("Triangle"), static_cast<int>(mapping_device_choice::TRIANGLE));
m_dropdown->addItem(tr("Cross"), static_cast<int>(mapping_device_choice::CROSS));
m_dropdown->addItem(tr("Square"), static_cast<int>(mapping_device_choice::SQUARE));
m_dropdown->addItem(tr("Circle"), static_cast<int>(mapping_device_choice::CIRCLE));
m_dropdown->addItem(tr("L2"), static_cast<int>(mapping_device_choice::L2));
m_dropdown->addItem(tr("L3"), static_cast<int>(mapping_device_choice::L3));
m_dropdown->addItem(tr("R2"), static_cast<int>(mapping_device_choice::R2));
m_dropdown->addItem(tr("R3"), static_cast<int>(mapping_device_choice::R3));
m_dropdown->addItem(tr("L4"), static_cast<int>(mapping_device_choice::PLUS));
m_dropdown->addItem(tr("L5"), static_cast<int>(mapping_device_choice::MINUS));
m_dropdown->addItem(tr("R4"), static_cast<int>(mapping_device_choice::DIAL_CLOCKWISE));
m_dropdown->addItem(tr("R5"), static_cast<int>(mapping_device_choice::DIAL_ANTICLOCKWISE));
m_dropdown->addItem(tr("Select"), static_cast<int>(mapping_device_choice::SELECT));
m_dropdown->addItem(tr("Pause"), static_cast<int>(mapping_device_choice::PAUSE));
m_dropdown->addItem(tr("Gear 1"), static_cast<int>(mapping_device_choice::SHIFTER_1));
m_dropdown->addItem(tr("Gear 2"), static_cast<int>(mapping_device_choice::SHIFTER_2));
m_dropdown->addItem(tr("Gear 3"), static_cast<int>(mapping_device_choice::SHIFTER_3));
m_dropdown->addItem(tr("Gear 4"), static_cast<int>(mapping_device_choice::SHIFTER_4));
m_dropdown->addItem(tr("Gear 5"), static_cast<int>(mapping_device_choice::SHIFTER_5));
m_dropdown->addItem(tr("Gear 6"), static_cast<int>(mapping_device_choice::SHIFTER_6));
m_dropdown->addItem(tr("Gear r"), static_cast<int>(mapping_device_choice::SHIFTER_R));
update_display(); update_display();
} }
mapping_device_choice get_device_choice() const mapping_device get_device_choice() const
{ {
return m_device_choice; return m_device_choice;
} }
void set_device_choice(mapping_device_choice choice) void set_device_choice(mapping_device choice)
{ {
m_device_choice = choice; m_device_choice = choice;
update_display(); update_display();
@ -168,7 +226,7 @@ private:
m_dropdown->setCurrentIndex(static_cast<int>(m_device_choice)); m_dropdown->setCurrentIndex(static_cast<int>(m_device_choice));
} }
mapping_device_choice m_device_choice = mapping_device_choice::NONE; mapping_device m_device_choice = mapping_device::NONE;
QComboBox* m_dropdown = nullptr; QComboBox* m_dropdown = nullptr;
QPushButton* m_disable_button = nullptr; QPushButton* m_disable_button = nullptr;
}; };
@ -195,7 +253,7 @@ public:
m_display_box->setTextFormat(Qt::RichText); m_display_box->setTextFormat(Qt::RichText);
m_display_box->setWordWrap(true); m_display_box->setWordWrap(true);
m_display_box->setFrameStyle(QFrame::Box); m_display_box->setFrameStyle(QFrame::Box);
m_display_box->setMinimumWidth(150); m_display_box->setMinimumWidth(225);
m_map_button = new QPushButton(tr("MAP"), horizontal_container); m_map_button = new QPushButton(tr("MAP"), horizontal_container);
m_unmap_button = new QPushButton(tr("UNMAP"), horizontal_container); m_unmap_button = new QPushButton(tr("UNMAP"), horizontal_container);
@ -217,13 +275,15 @@ public:
update_display(); update_display();
horizontal_layout->addWidget(label); horizontal_layout->addWidget(label, 1);
horizontal_layout->addWidget(m_display_box); horizontal_layout->addWidget(m_display_box, 2);
if (m_button_status) if (m_button_status)
horizontal_layout->addWidget(m_button_status); horizontal_layout->addWidget(m_button_status, 1);
horizontal_layout->addWidget(m_map_button); else
horizontal_layout->addWidget(m_unmap_button); horizontal_layout->addStretch(1); // For a more consistent layout
horizontal_layout->addWidget(m_reverse_checkbox); horizontal_layout->addWidget(m_map_button, 1);
horizontal_layout->addWidget(m_unmap_button, 1);
horizontal_layout->addWidget(m_reverse_checkbox, 1);
if (m_axis_status) if (m_axis_status)
layout->addWidget(m_axis_status); layout->addWidget(m_axis_status);
@ -253,7 +313,7 @@ public:
if (m_mapping_in_progress) if (m_mapping_in_progress)
{ {
const int timeout_sec = m_timeout_msec / 1000; const int timeout_sec = m_timeout_msec / 1000;
const std::map<u32, joystick_state>& new_joystick_states = m_setting_dialog->get_joystick_states(); const std::map<u64, joystick_state>& new_joystick_states = m_setting_dialog->get_joystick_states();
m_setting_dialog->set_state_text(tr("Input %0 for %1, timeout in %2 %3").arg(m_is_axis ? tr("axis") : tr("button/hat")).arg(m_name).arg(timeout_sec).arg(timeout_sec >= 2 ? tr("seconds") : tr("second"))); m_setting_dialog->set_state_text(tr("Input %0 for %1, timeout in %2 %3").arg(m_is_axis ? tr("axis") : tr("button/hat")).arg(m_name).arg(timeout_sec).arg(timeout_sec >= 2 ? tr("seconds") : tr("second")));
@ -270,7 +330,7 @@ public:
constexpr s16 axis_change_threshold = 0x7FFF / 5; constexpr s16 axis_change_threshold = 0x7FFF / 5;
if (last_joystick_state->second.axes.size() != new_joystick_state.axes.size()) if (last_joystick_state->second.axes.size() != new_joystick_state.axes.size())
{ {
logitech_g27_cfg_log.error("During input state change diff, number of axes on %04x:%04x changed", device_type_id >> 16, device_type_id & 0xFFFF); logitech_g27_cfg_log.error("During input state change diff, number of axes on %04x:%04x changed", (device_type_id >> 16) & 0xFFFF, device_type_id & 0xFFFF);
continue; continue;
} }
for (usz i = 0; i < new_joystick_state.axes.size(); i++) for (usz i = 0; i < new_joystick_state.axes.size(); i++)
@ -293,12 +353,12 @@ public:
{ {
if (last_joystick_state->second.buttons.size() != new_joystick_state.buttons.size()) if (last_joystick_state->second.buttons.size() != new_joystick_state.buttons.size())
{ {
logitech_g27_cfg_log.error("during input state change diff, number of buttons on %04x:%04x changed", device_type_id >> 16, device_type_id & 0xFFFF); logitech_g27_cfg_log.error("during input state change diff, number of buttons on %04x:%04x changed", (device_type_id >> 16) & 0xFFFF, device_type_id & 0xFFFF);
continue; continue;
} }
if (last_joystick_state->second.hats.size() != new_joystick_state.hats.size()) if (last_joystick_state->second.hats.size() != new_joystick_state.hats.size())
{ {
logitech_g27_cfg_log.error("during input state change diff, number of hats on %04x:%04x changed", device_type_id >> 16, device_type_id & 0xFFFF); logitech_g27_cfg_log.error("during input state change diff, number of hats on %04x:%04x changed", (device_type_id >> 16) & 0xFFFF, device_type_id & 0xFFFF);
continue; continue;
} }
for (usz i = 0; i < new_joystick_state.buttons.size(); i++) for (usz i = 0; i < new_joystick_state.buttons.size(); i++)
@ -381,14 +441,14 @@ private:
bool m_mapping_in_progress = false; bool m_mapping_in_progress = false;
int m_timeout_msec = 5500; int m_timeout_msec = 5500;
QTimer* m_tick_timer = nullptr; QTimer* m_tick_timer = nullptr;
std::map<u32, joystick_state> m_last_joystick_states; std::map<u64, joystick_state> m_last_joystick_states;
QCheckBox* m_button_status = nullptr; QCheckBox* m_button_status = nullptr;
QSlider* m_axis_status = nullptr; QSlider* m_axis_status = nullptr;
void update_display() void update_display()
{ {
const std::string text = fmt::format("%04x:%04x, %s %u %s", m_mapping.device_type_id >> 16, m_mapping.device_type_id & 0xFFFF, m_mapping.type, m_mapping.id, m_mapping.hat); const std::string text = fmt::format("%04x:%04x (0x%08x), %s %u %s", (m_mapping.device_type_id >> 16) & 0xFFFF, m_mapping.device_type_id & 0xFFFF, m_mapping.device_type_id >> 32, m_mapping.type, m_mapping.id, m_mapping.hat);
m_display_box->setText(QString::fromStdString(text)); m_display_box->setText(QString::fromStdString(text));
m_reverse_checkbox->setChecked(m_mapping.reverse); m_reverse_checkbox->setChecked(m_mapping.reverse);
@ -406,7 +466,7 @@ private:
m_axis_status->setValue(std::clamp(axis_value, -0x8000, 0x7FFF)); m_axis_status->setValue(std::clamp(axis_value, -0x8000, 0x7FFF));
} }
const std::map<u32, joystick_state>& joystick_states = m_setting_dialog->get_joystick_states(); const std::map<u64, joystick_state>& joystick_states = m_setting_dialog->get_joystick_states();
auto joystick_state = joystick_states.find(m_mapping.device_type_id); auto joystick_state = joystick_states.find(m_mapping.device_type_id);
if (joystick_state != joystick_states.end()) if (joystick_state != joystick_states.end())
@ -452,14 +512,16 @@ private:
void emulated_logitech_g27_settings_dialog::save_ui_state_to_config() void emulated_logitech_g27_settings_dialog::save_ui_state_to_config()
{ {
const auto save_mapping = [this](emulated_logitech_g27_mapping& mapping, Mapping* ui_mapping, mapping_device_choice device_choice) const auto save_mapping = [this](mapping_device device_choice)
{ {
const sdl_mapping& m = ui_mapping->get_mapping(); emulated_logitech_g27_mapping& mapping = device_cfg(device_choice);
const sdl_mapping& m = ::at32(m_mappings, device_choice)->get_mapping();
mapping.device_type_id.set(m.device_type_id); mapping.device_type_id.set(m.device_type_id);
mapping.type.set(m.type); mapping.type.set(m.type);
mapping.id.set(m.id); mapping.id.set(m.id);
mapping.hat.set(m.hat); mapping.hat.set(m.hat);
mapping.reverse.set(m.reverse); mapping.reverse.set(m.reverse);
if (m_ffb_device->get_device_choice() == device_choice) if (m_ffb_device->get_device_choice() == device_choice)
{ {
g_cfg_logitech_g27.ffb_device_type_id.set(m.device_type_id); g_cfg_logitech_g27.ffb_device_type_id.set(m.device_type_id);
@ -470,56 +532,20 @@ void emulated_logitech_g27_settings_dialog::save_ui_state_to_config()
} }
}; };
auto& cfg = g_cfg_logitech_g27; for (int i = 0; i < static_cast<int>(mapping_device::COUNT); i++)
{
save_mapping(cfg.steering, m_steering, mapping_device_choice::STEERING); save_mapping(static_cast<mapping_device>(i));
save_mapping(cfg.throttle, m_throttle, mapping_device_choice::THROTTLE); }
save_mapping(cfg.brake, m_brake, mapping_device_choice::BRAKE);
save_mapping(cfg.clutch, m_clutch, mapping_device_choice::CLUTCH);
save_mapping(cfg.shift_up, m_shift_up, mapping_device_choice::SHIFT_UP);
save_mapping(cfg.shift_down, m_shift_down, mapping_device_choice::SHIFT_DOWN);
save_mapping(cfg.up, m_up, mapping_device_choice::UP);
save_mapping(cfg.down, m_down, mapping_device_choice::DOWN);
save_mapping(cfg.left, m_left, mapping_device_choice::LEFT);
save_mapping(cfg.right, m_right, mapping_device_choice::RIGHT);
save_mapping(cfg.triangle, m_triangle, mapping_device_choice::TRIANGLE);
save_mapping(cfg.cross, m_cross, mapping_device_choice::CROSS);
save_mapping(cfg.square, m_square, mapping_device_choice::SQUARE);
save_mapping(cfg.circle, m_circle, mapping_device_choice::CIRCLE);
save_mapping(cfg.l2, m_l2, mapping_device_choice::L2);
save_mapping(cfg.l3, m_l3, mapping_device_choice::L3);
save_mapping(cfg.r2, m_r2, mapping_device_choice::R2);
save_mapping(cfg.r3, m_r3, mapping_device_choice::R3);
save_mapping(cfg.plus, m_plus, mapping_device_choice::PLUS);
save_mapping(cfg.minus, m_minus, mapping_device_choice::MINUS);
save_mapping(cfg.dial_clockwise, m_dial_clockwise, mapping_device_choice::DIAL_CLOCKWISE);
save_mapping(cfg.dial_anticlockwise, m_dial_anticlockwise, mapping_device_choice::DIAL_ANTICLOCKWISE);
save_mapping(cfg.select, m_select, mapping_device_choice::SELECT);
save_mapping(cfg.pause, m_pause, mapping_device_choice::PAUSE);
save_mapping(cfg.shifter_1, m_shifter_1, mapping_device_choice::SHIFTER_1);
save_mapping(cfg.shifter_2, m_shifter_2, mapping_device_choice::SHIFTER_2);
save_mapping(cfg.shifter_3, m_shifter_3, mapping_device_choice::SHIFTER_3);
save_mapping(cfg.shifter_4, m_shifter_4, mapping_device_choice::SHIFTER_4);
save_mapping(cfg.shifter_5, m_shifter_5, mapping_device_choice::SHIFTER_5);
save_mapping(cfg.shifter_6, m_shifter_6, mapping_device_choice::SHIFTER_6);
save_mapping(cfg.shifter_r, m_shifter_r, mapping_device_choice::SHIFTER_R);
g_cfg_logitech_g27.enabled.set(m_enabled->isChecked()); g_cfg_logitech_g27.enabled.set(m_enabled->isChecked());
g_cfg_logitech_g27.reverse_effects.set(m_reverse_effects->isChecked()); g_cfg_logitech_g27.reverse_effects.set(m_reverse_effects->isChecked());
if (m_ffb_device->get_device_choice() == mapping_device_choice::NONE) if (m_ffb_device->get_device_choice() == mapping_device::NONE)
{ {
g_cfg_logitech_g27.ffb_device_type_id.set(0); g_cfg_logitech_g27.ffb_device_type_id.set(0);
} }
if (m_led_device->get_device_choice() == mapping_device_choice::NONE) if (m_led_device->get_device_choice() == mapping_device::NONE)
{ {
g_cfg_logitech_g27.led_device_type_id.set(0); g_cfg_logitech_g27.led_device_type_id.set(0);
} }
@ -527,8 +553,9 @@ void emulated_logitech_g27_settings_dialog::save_ui_state_to_config()
void emulated_logitech_g27_settings_dialog::load_ui_state_from_config() void emulated_logitech_g27_settings_dialog::load_ui_state_from_config()
{ {
const auto load_mapping = [this](const emulated_logitech_g27_mapping& mapping, Mapping* ui_mapping, mapping_device_choice device_choice) const auto load_mapping = [this](mapping_device device_choice)
{ {
const emulated_logitech_g27_mapping& mapping = device_cfg(device_choice);
const sdl_mapping m = const sdl_mapping m =
{ {
.device_type_id = mapping.device_type_id.get(), .device_type_id = mapping.device_type_id.get(),
@ -538,57 +565,26 @@ void emulated_logitech_g27_settings_dialog::load_ui_state_from_config()
.reverse = mapping.reverse.get(), .reverse = mapping.reverse.get(),
.positive_axis = false .positive_axis = false
}; };
ui_mapping->set_mapping(m);
if (g_cfg_logitech_g27.ffb_device_type_id.get() == m.device_type_id && m_ffb_device->get_device_choice() == mapping_device_choice::NONE) ::at32(m_mappings, device_choice)->set_mapping(m);
const u64 ffb_device_type_id = g_cfg_logitech_g27.ffb_device_type_id.get();
const u64 led_device_type_id = g_cfg_logitech_g27.led_device_type_id.get();
if (ffb_device_type_id == m.device_type_id && m_ffb_device->get_device_choice() == mapping_device::NONE)
{ {
m_ffb_device->set_device_choice(device_choice); m_ffb_device->set_device_choice(device_choice);
} }
if (g_cfg_logitech_g27.led_device_type_id.get() == m.device_type_id && m_led_device->get_device_choice() == mapping_device_choice::NONE) if (led_device_type_id == m.device_type_id && m_led_device->get_device_choice() == mapping_device::NONE)
{ {
m_led_device->set_device_choice(device_choice); m_led_device->set_device_choice(device_choice);
} }
}; };
const auto& cfg = g_cfg_logitech_g27; for (int i = 0; i < static_cast<int>(mapping_device::COUNT); i++)
{
load_mapping(cfg.steering, m_steering, mapping_device_choice::STEERING); load_mapping(static_cast<mapping_device>(i));
load_mapping(cfg.throttle, m_throttle, mapping_device_choice::THROTTLE); }
load_mapping(cfg.brake, m_brake, mapping_device_choice::BRAKE);
load_mapping(cfg.clutch, m_clutch, mapping_device_choice::CLUTCH);
load_mapping(cfg.shift_up, m_shift_up, mapping_device_choice::SHIFT_UP);
load_mapping(cfg.shift_down, m_shift_down, mapping_device_choice::SHIFT_DOWN);
load_mapping(cfg.up, m_up, mapping_device_choice::UP);
load_mapping(cfg.down, m_down, mapping_device_choice::DOWN);
load_mapping(cfg.left, m_left, mapping_device_choice::LEFT);
load_mapping(cfg.right, m_right, mapping_device_choice::RIGHT);
load_mapping(cfg.triangle, m_triangle, mapping_device_choice::TRIANGLE);
load_mapping(cfg.cross, m_cross, mapping_device_choice::CROSS);
load_mapping(cfg.square, m_square, mapping_device_choice::SQUARE);
load_mapping(cfg.circle, m_circle, mapping_device_choice::CIRCLE);
load_mapping(cfg.l2, m_l2, mapping_device_choice::L2);
load_mapping(cfg.l3, m_l3, mapping_device_choice::L3);
load_mapping(cfg.r2, m_r2, mapping_device_choice::R2);
load_mapping(cfg.r3, m_r3, mapping_device_choice::R3);
load_mapping(cfg.plus, m_plus, mapping_device_choice::PLUS);
load_mapping(cfg.minus, m_minus, mapping_device_choice::MINUS);
load_mapping(cfg.dial_clockwise, m_dial_clockwise, mapping_device_choice::DIAL_CLOCKWISE);
load_mapping(cfg.dial_anticlockwise, m_dial_anticlockwise, mapping_device_choice::DIAL_ANTICLOCKWISE);
load_mapping(cfg.select, m_select, mapping_device_choice::SELECT);
load_mapping(cfg.pause, m_pause, mapping_device_choice::PAUSE);
load_mapping(cfg.shifter_1, m_shifter_1, mapping_device_choice::SHIFTER_1);
load_mapping(cfg.shifter_2, m_shifter_2, mapping_device_choice::SHIFTER_2);
load_mapping(cfg.shifter_3, m_shifter_3, mapping_device_choice::SHIFTER_3);
load_mapping(cfg.shifter_4, m_shifter_4, mapping_device_choice::SHIFTER_4);
load_mapping(cfg.shifter_5, m_shifter_5, mapping_device_choice::SHIFTER_5);
load_mapping(cfg.shifter_6, m_shifter_6, mapping_device_choice::SHIFTER_6);
load_mapping(cfg.shifter_r, m_shifter_r, mapping_device_choice::SHIFTER_R);
m_enabled->setChecked(g_cfg_logitech_g27.enabled.get()); m_enabled->setChecked(g_cfg_logitech_g27.enabled.get());
m_reverse_effects->setChecked(g_cfg_logitech_g27.reverse_effects.get()); m_reverse_effects->setChecked(g_cfg_logitech_g27.reverse_effects.get());
@ -630,7 +626,6 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi
return; return;
g_cfg_logitech_g27.reset(); g_cfg_logitech_g27.reset();
load_ui_state_from_config(); load_ui_state_from_config();
g_cfg_logitech_g27.save();
} }
else if (button == buttons->button(QDialogButtonBox::Cancel)) else if (button == buttons->button(QDialogButtonBox::Cancel))
{ {
@ -639,10 +634,14 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi
}); });
QLabel* warning = new QLabel(tr("Warning: Force feedback output were meant for Logitech G27, on stronger wheels please adjust force strength accordingly in your wheel software."), this); QLabel* warning = new QLabel(tr("Warning: Force feedback output were meant for Logitech G27, on stronger wheels please adjust force strength accordingly in your wheel software."), this);
warning->setStyleSheet("color: red;"); warning->setStyleSheet(QString("color: %0;").arg(gui::utils::get_label_color("emulated_logitech_g27_warning_label", Qt::red, Qt::red).name()));
warning->setWordWrap(true); warning->setWordWrap(true);
v_layout->addWidget(warning); v_layout->addWidget(warning);
QLabel* mapping_note = new QLabel(tr("Note: Please DO NOT map your wheel onto gamepads, only map it here. If your wheel was mapped onto gamepads, go to gamepad settings and unmap it. If you used vJoy to map your wheel onto a gamepad before for RPCS3, undo that."), this);
mapping_note->setWordWrap(true);
v_layout->addWidget(mapping_note);
m_enabled = new QCheckBox(tr("Enabled (requires game restart)"), this); m_enabled = new QCheckBox(tr("Enabled (requires game restart)"), this);
v_layout->addWidget(m_enabled); v_layout->addWidget(m_enabled);
@ -670,54 +669,30 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi
QLabel* axis_label = new QLabel(tr("Axes:"), mapping_widget); QLabel* axis_label = new QLabel(tr("Axes:"), mapping_widget);
mapping_layout->addWidget(axis_label); mapping_layout->addWidget(axis_label);
const auto add_mapping_setting = [mapping_widget, this, mapping_layout](Mapping*& target, bool is_axis, const QString& display_name, bool flip_axis_display) const auto add_axis = [this, mapping_widget, mapping_layout](mapping_device dev, bool flip_axis_display)
{ {
target = new Mapping(mapping_widget, this, is_axis, display_name, flip_axis_display); m_mappings[dev] = new Mapping(mapping_widget, this, true, device_name(dev), flip_axis_display);
mapping_layout->addWidget(target); mapping_layout->addWidget(m_mappings[dev]);
}; };
add_mapping_setting(m_steering, true, tr("Steering"), false); const auto add_button = [this, mapping_widget, mapping_layout](mapping_device dev)
add_mapping_setting(m_throttle, true, tr("Throttle"), true); {
add_mapping_setting(m_brake, true, tr("Brake"), true); m_mappings[dev] = new Mapping(mapping_widget, this, false, device_name(dev), false);
add_mapping_setting(m_clutch, true, tr("Clutch"), true); mapping_layout->addWidget(m_mappings[dev]);
};
add_axis(mapping_device::STEERING, false);
add_axis(mapping_device::THROTTLE, true);
add_axis(mapping_device::BRAKE, true);
add_axis(mapping_device::CLUTCH, true);
QLabel* button_label = new QLabel(tr("Buttons:"), mapping_widget); QLabel* button_label = new QLabel(tr("Buttons:"), mapping_widget);
mapping_layout->addWidget(button_label); mapping_layout->addWidget(button_label);
add_mapping_setting(m_shift_up, false, tr("Shift up"), false); for (int i = static_cast<int>(mapping_device::FIRST_BUTTON); i < static_cast<int>(mapping_device::COUNT); i++)
add_mapping_setting(m_shift_down, false, tr("Shift down"), false); {
add_button(static_cast<mapping_device>(i));
add_mapping_setting(m_up, false, tr("Up"), false); }
add_mapping_setting(m_down, false, tr("Down"), false);
add_mapping_setting(m_left, false, tr("Left"), false);
add_mapping_setting(m_right, false, tr("Right"), false);
add_mapping_setting(m_triangle, false, tr("Triangle"), false);
add_mapping_setting(m_cross, false, tr("Cross"), false);
add_mapping_setting(m_square, false, tr("Square"), false);
add_mapping_setting(m_circle, false, tr("Circle"), false);
add_mapping_setting(m_l2, false, tr("L2"), false);
add_mapping_setting(m_l3, false, tr("L3"), false);
add_mapping_setting(m_r2, false, tr("R2"), false);
add_mapping_setting(m_r3, false, tr("R3"), false);
add_mapping_setting(m_plus, false, tr("L4"), false);
add_mapping_setting(m_minus, false, tr("L5"), false);
add_mapping_setting(m_dial_clockwise, false, tr("R4"), false);
add_mapping_setting(m_dial_anticlockwise, false, tr("R5"), false);
add_mapping_setting(m_select, false, tr("Select"), false);
add_mapping_setting(m_pause, false, tr("Start"), false);
add_mapping_setting(m_shifter_1, false, tr("Gear 1"), false);
add_mapping_setting(m_shifter_2, false, tr("Gear 2"), false);
add_mapping_setting(m_shifter_3, false, tr("Gear 3"), false);
add_mapping_setting(m_shifter_4, false, tr("Gear 4"), false);
add_mapping_setting(m_shifter_5, false, tr("Gear 5"), false);
add_mapping_setting(m_shifter_6, false, tr("Gear 6"), false);
add_mapping_setting(m_shifter_r, false, tr("Gear R"), false);
v_layout->addSpacing(20); v_layout->addSpacing(20);
@ -727,10 +702,10 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi
v_layout->addWidget(buttons); v_layout->addWidget(buttons);
setLayout(v_layout); setLayout(v_layout);
load_ui_state_from_config();
m_sdl_initialized = sdl_instance::get_instance().initialize(); m_sdl_initialized = sdl_instance::get_instance().initialize();
load_ui_state_from_config();
if (m_sdl_initialized) if (m_sdl_initialized)
get_joystick_states(); get_joystick_states();
} }
@ -769,7 +744,7 @@ static inline hat_component get_sdl_hat_component(u8 sdl_hat)
return hat_component::none; return hat_component::none;
} }
const std::map<u32, joystick_state>& emulated_logitech_g27_settings_dialog::get_joystick_states() const std::map<u64, joystick_state>& emulated_logitech_g27_settings_dialog::get_joystick_states()
{ {
if (!m_sdl_initialized) if (!m_sdl_initialized)
{ {
@ -785,7 +760,7 @@ const std::map<u32, joystick_state>& emulated_logitech_g27_settings_dialog::get_
m_last_joystick_states_update = now; m_last_joystick_states_update = now;
std::map<u32, joystick_state> new_joystick_states; std::map<u64, joystick_state> new_joystick_states;
std::vector<SDL_Joystick*> new_joystick_handles; std::vector<SDL_Joystick*> new_joystick_handles;
sdl_instance::get_instance().pump_events(); sdl_instance::get_instance().pump_events();
@ -802,15 +777,23 @@ const std::map<u32, joystick_state>& emulated_logitech_g27_settings_dialog::get_
} }
new_joystick_handles.push_back(cur_joystick); new_joystick_handles.push_back(cur_joystick);
const u32 device_type_id = (SDL_GetJoystickVendor(cur_joystick) << 16) | SDL_GetJoystickProduct(cur_joystick); const int num_axes = SDL_GetNumJoystickAxes(cur_joystick);
const int num_buttons = SDL_GetNumJoystickButtons(cur_joystick);
const int num_hats = SDL_GetNumJoystickHats(cur_joystick);
const emulated_g27_device_type_id device_type_id_struct =
{
.product_id = static_cast<u64>(SDL_GetJoystickProduct(cur_joystick)),
.vendor_id = static_cast<u64>(SDL_GetJoystickVendor(cur_joystick)),
.num_axes = static_cast<u64>(num_axes),
.num_hats = static_cast<u64>(num_hats),
.num_buttons = static_cast<u64>(num_buttons)
};
const u64 device_type_id = device_type_id_struct.as_u64();
auto cur_state = new_joystick_states.find(device_type_id); auto cur_state = new_joystick_states.find(device_type_id);
if (cur_state == new_joystick_states.end()) if (cur_state == new_joystick_states.end())
{ {
joystick_state s {}; joystick_state s {};
const int num_axes = SDL_GetNumJoystickAxes(cur_joystick);
const int num_buttons = SDL_GetNumJoystickButtons(cur_joystick);
const int num_hats = SDL_GetNumJoystickHats(cur_joystick);
for (int j = 0; j < num_axes; j++) for (int j = 0; j < num_axes; j++)
{ {
s.axes.push_back(SDL_GetJoystickAxis(cur_joystick, j)); s.axes.push_back(SDL_GetJoystickAxis(cur_joystick, j));
@ -824,7 +807,7 @@ const std::map<u32, joystick_state>& emulated_logitech_g27_settings_dialog::get_
const u8 sdl_hat = SDL_GetJoystickHat(cur_joystick, j); const u8 sdl_hat = SDL_GetJoystickHat(cur_joystick, j);
s.hats.push_back(get_sdl_hat_component(sdl_hat)); s.hats.push_back(get_sdl_hat_component(sdl_hat));
} }
new_joystick_states[device_type_id] = s; new_joystick_states[device_type_id] = std::move(s);
} }
else else
{ {
@ -868,44 +851,10 @@ void emulated_logitech_g27_settings_dialog::set_enable(bool enable)
{ {
const int slider_position = m_mapping_scroll_area->verticalScrollBar()->sliderPosition(); const int slider_position = m_mapping_scroll_area->verticalScrollBar()->sliderPosition();
m_steering->set_enable(enable); for (auto& [dev, mapping] : m_mappings)
m_throttle->set_enable(enable); {
m_brake->set_enable(enable); mapping->set_enable(enable);
m_clutch->set_enable(enable); }
m_shift_up->set_enable(enable);
m_shift_down->set_enable(enable);
m_up->set_enable(enable);
m_down->set_enable(enable);
m_left->set_enable(enable);
m_right->set_enable(enable);
m_triangle->set_enable(enable);
m_cross->set_enable(enable);
m_square->set_enable(enable);
m_circle->set_enable(enable);
m_l2->set_enable(enable);
m_l3->set_enable(enable);
m_r2->set_enable(enable);
m_r3->set_enable(enable);
m_plus->set_enable(enable);
m_minus->set_enable(enable);
m_dial_clockwise->set_enable(enable);
m_dial_anticlockwise->set_enable(enable);
m_select->set_enable(enable);
m_pause->set_enable(enable);
m_shifter_1->set_enable(enable);
m_shifter_2->set_enable(enable);
m_shifter_3->set_enable(enable);
m_shifter_4->set_enable(enable);
m_shifter_5->set_enable(enable);
m_shifter_6->set_enable(enable);
m_shifter_r->set_enable(enable);
m_enabled->setEnabled(enable); m_enabled->setEnabled(enable);
m_reverse_effects->setEnabled(enable); m_reverse_effects->setEnabled(enable);

View file

@ -30,6 +30,8 @@ struct joystick_state
class Mapping; class Mapping;
class DeviceChoice; class DeviceChoice;
enum class mapping_device;
class emulated_logitech_g27_settings_dialog : public QDialog class emulated_logitech_g27_settings_dialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
@ -38,14 +40,14 @@ public:
emulated_logitech_g27_settings_dialog(QWidget* parent = nullptr); emulated_logitech_g27_settings_dialog(QWidget* parent = nullptr);
virtual ~emulated_logitech_g27_settings_dialog(); virtual ~emulated_logitech_g27_settings_dialog();
void set_state_text(const QString& text); void set_state_text(const QString& text);
const std::map<u32, joystick_state>& get_joystick_states(); const std::map<u64, joystick_state>& get_joystick_states();
void set_enable(bool enable); void set_enable(bool enable);
private: private:
void load_ui_state_from_config(); void load_ui_state_from_config();
void save_ui_state_to_config(); void save_ui_state_to_config();
std::map<u32, joystick_state> m_last_joystick_states; std::map<u64, joystick_state> m_last_joystick_states;
std::vector<SDL_Joystick*> m_joystick_handles; std::vector<SDL_Joystick*> m_joystick_handles;
uint64_t m_last_joystick_states_update = 0; uint64_t m_last_joystick_states_update = 0;
bool m_sdl_initialized = false; bool m_sdl_initialized = false;
@ -56,44 +58,7 @@ private:
QCheckBox* m_enabled = nullptr; QCheckBox* m_enabled = nullptr;
QCheckBox* m_reverse_effects = nullptr; QCheckBox* m_reverse_effects = nullptr;
Mapping* m_steering = nullptr; std::map<mapping_device, Mapping*> m_mappings;
Mapping* m_throttle = nullptr;
Mapping* m_brake = nullptr;
Mapping* m_clutch = nullptr;
Mapping* m_shift_up = nullptr;
Mapping* m_shift_down = nullptr;
Mapping* m_up = nullptr;
Mapping* m_down = nullptr;
Mapping* m_left = nullptr;
Mapping* m_right = nullptr;
Mapping* m_triangle = nullptr;
Mapping* m_cross = nullptr;
Mapping* m_square = nullptr;
Mapping* m_circle = nullptr;
Mapping* m_l2 = nullptr;
Mapping* m_l3 = nullptr;
Mapping* m_r2 = nullptr;
Mapping* m_r3 = nullptr;
Mapping* m_plus = nullptr;
Mapping* m_minus = nullptr;
Mapping* m_dial_clockwise = nullptr;
Mapping* m_dial_anticlockwise = nullptr;
Mapping* m_select = nullptr;
Mapping* m_pause = nullptr;
Mapping* m_shifter_1 = nullptr;
Mapping* m_shifter_2 = nullptr;
Mapping* m_shifter_3 = nullptr;
Mapping* m_shifter_4 = nullptr;
Mapping* m_shifter_5 = nullptr;
Mapping* m_shifter_6 = nullptr;
Mapping* m_shifter_r = nullptr;
DeviceChoice* m_ffb_device = nullptr; DeviceChoice* m_ffb_device = nullptr;
DeviceChoice* m_led_device = nullptr; DeviceChoice* m_led_device = nullptr;

View file

@ -231,13 +231,9 @@ pad_motion_settings_dialog::pad_motion_settings_dialog(QDialog* parent, std::sha
pad_motion_settings_dialog::~pad_motion_settings_dialog() pad_motion_settings_dialog::~pad_motion_settings_dialog()
{ {
if (m_input_thread) // Join thread
{ m_input_thread_state = input_thread_state::pausing;
m_input_thread_state = input_thread_state::pausing; m_input_thread.reset();
auto& thread = *m_input_thread;
thread = thread_state::aborting;
thread();
}
} }
void pad_motion_settings_dialog::change_device(int index) void pad_motion_settings_dialog::change_device(int index)

View file

@ -269,13 +269,8 @@ ps_move_tracker_dialog::~ps_move_tracker_dialog()
m_camera_handler->close_camera(); m_camera_handler->close_camera();
} }
if (m_input_thread) // Join thread
{ m_input_thread.reset();
auto& thread = *m_input_thread;
thread = thread_state::aborting;
thread();
m_input_thread.reset();
}
} }
void ps_move_tracker_dialog::update_color(bool update_sliders) void ps_move_tracker_dialog::update_color(bool update_sliders)

View file

@ -827,10 +827,7 @@ namespace utils
} }
} }
auto& thread = *m_thread; // Join thread
thread = thread_state::aborting;
thread();
m_thread.reset(); m_thread.reset();
} }