ps move: allow to configure mouse move handler buttons

This commit is contained in:
Megamouse 2025-01-09 21:10:28 +01:00
parent 7e03828f35
commit a0df1e09a6
14 changed files with 273 additions and 65 deletions

View file

@ -40,9 +40,18 @@ void fmt_class_string<gem_btn>::format(std::string& out, u64 arg)
case gem_btn::square: return "Square"; case gem_btn::square: return "Square";
case gem_btn::move: return "Move"; case gem_btn::move: return "Move";
case gem_btn::t: return "T"; case gem_btn::t: return "T";
case gem_btn::count: return "Count";
case gem_btn::x_axis: return "X-Axis"; case gem_btn::x_axis: return "X-Axis";
case gem_btn::y_axis: return "Y-Axis"; case gem_btn::y_axis: return "Y-Axis";
case gem_btn::combo: return "Combo";
case gem_btn::combo_start: return "Combo Start";
case gem_btn::combo_select: return "Combo Select";
case gem_btn::combo_triangle: return "Combo Triangle";
case gem_btn::combo_circle: return "Combo Circle";
case gem_btn::combo_cross: return "Combo Cross";
case gem_btn::combo_square: return "Combo Square";
case gem_btn::combo_move: return "Combo Move";
case gem_btn::combo_t: return "Combo T";
case gem_btn::count: return "Count";
} }
return unknown; return unknown;
@ -177,6 +186,7 @@ using gun_thread = named_thread<gun_handler>;
cfg_gems g_cfg_gem_real; cfg_gems g_cfg_gem_real;
cfg_fake_gems g_cfg_gem_fake; cfg_fake_gems g_cfg_gem_fake;
cfg_mouse_gems g_cfg_gem_mouse;
struct gem_config_data struct gem_config_data
{ {
@ -494,8 +504,14 @@ public:
cellGem.notice("Could not load fake gem config. Using defaults."); cellGem.notice("Could not load fake gem config. Using defaults.");
} }
if (!g_cfg_gem_mouse.load())
{
cellGem.notice("Could not load mouse gem config. Using defaults.");
}
cellGem.notice("Real gem config=\n", g_cfg_gem_real.to_string()); cellGem.notice("Real gem config=\n", g_cfg_gem_real.to_string());
cellGem.notice("Fake gem config=\n", g_cfg_gem_fake.to_string()); cellGem.notice("Fake gem config=\n", g_cfg_gem_fake.to_string());
cellGem.notice("Mouse gem config=\n", g_cfg_gem_mouse.to_string());
} }
}; };
@ -1574,7 +1590,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t<u16>& digital_buttons, be_t
return; return;
} }
const auto handle_input = [&](gem_btn btn, u16 value, bool pressed) const auto handle_input = [&](gem_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;
@ -1606,9 +1622,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t<u16>& digital_buttons, be_t
digital_buttons |= CELL_GEM_CTRL_T; digital_buttons |= CELL_GEM_CTRL_T;
analog_t = std::max<u16>(analog_t, value); analog_t = std::max<u16>(analog_t, value);
break; break;
case gem_btn::x_axis: default:
case gem_btn::y_axis:
case gem_btn::count:
break; break;
} }
}; };
@ -1632,7 +1646,7 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>&
y_pos = 0; y_pos = 0;
const auto& cfg = ::at32(g_cfg_gem_fake.players, gem_num); const auto& cfg = ::at32(g_cfg_gem_fake.players, gem_num);
cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed) cfg->handle_input(pad, true, [&](gem_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;
@ -1828,41 +1842,97 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t<u16>& digital_buttons, be_t<u1
return false; return false;
} }
std::set<MouseButtonCodes> pressed_buttons;
const Mouse& mouse_data = ::at32(handler.GetMice(), mouse_no); const Mouse& mouse_data = ::at32(handler.GetMice(), mouse_no);
const auto is_pressed = [&mouse_data, &pressed_buttons](MouseButtonCodes button) -> bool auto& cfg = ::at32(g_cfg_gem_mouse.players, mouse_no);
bool combo_active = false;
std::set<pad_button> combos;
static const std::unordered_map<gem_btn, u16> btn_map =
{ {
// Only allow each button to be used for one action unless it's the combo button. { gem_btn::start, CELL_GEM_CTRL_START },
return (mouse_data.buttons & button) && (button == (CELL_MOUSE_BUTTON_3 + 0u/*fix warning*/) || pressed_buttons.insert(button).second); { gem_btn::select, CELL_GEM_CTRL_SELECT },
{ gem_btn::triangle, CELL_GEM_CTRL_TRIANGLE },
{ gem_btn::circle, CELL_GEM_CTRL_CIRCLE },
{ gem_btn::cross, CELL_GEM_CTRL_CROSS },
{ gem_btn::square, CELL_GEM_CTRL_SQUARE },
{ gem_btn::move, CELL_GEM_CTRL_MOVE },
{ gem_btn::t, CELL_GEM_CTRL_T },
{ gem_btn::combo_start, CELL_GEM_CTRL_START },
{ gem_btn::combo_select, CELL_GEM_CTRL_SELECT },
{ gem_btn::combo_triangle, CELL_GEM_CTRL_TRIANGLE },
{ gem_btn::combo_circle, CELL_GEM_CTRL_CIRCLE },
{ gem_btn::combo_cross, CELL_GEM_CTRL_CROSS },
{ gem_btn::combo_square, CELL_GEM_CTRL_SQUARE },
{ gem_btn::combo_move, CELL_GEM_CTRL_MOVE },
{ gem_btn::combo_t, CELL_GEM_CTRL_T },
}; };
digital_buttons = 0; // Check combo button first
cfg->handle_input(mouse_data, [&combo_active](gem_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& abort)
{
if (pressed && btn == gem_btn::combo)
{
combo_active = true;
abort = true;
}
});
if ((is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_1)) || is_pressed(CELL_MOUSE_BUTTON_6)) // Check combos
digital_buttons |= CELL_GEM_CTRL_SELECT; if (combo_active)
{
cfg->handle_input(mouse_data, [&digital_buttons, &combos](gem_btn btn, pad_button pad_btn, u16 /*value*/, bool pressed, bool& /*abort*/)
{
if (!pressed)
return;
if ((is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_2)) || is_pressed(CELL_MOUSE_BUTTON_7)) switch (btn)
digital_buttons |= CELL_GEM_CTRL_START; {
case gem_btn::combo_start:
case gem_btn::combo_select:
case gem_btn::combo_triangle:
case gem_btn::combo_circle:
case gem_btn::combo_cross:
case gem_btn::combo_square:
case gem_btn::combo_move:
case gem_btn::combo_t:
digital_buttons |= ::at32(btn_map, btn);
combos.insert(pad_btn);
break;
default:
break;
}
});
}
if ((is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_4)) || is_pressed(CELL_MOUSE_BUTTON_8)) // Check normal buttons
digital_buttons |= CELL_GEM_CTRL_TRIANGLE; cfg->handle_input(mouse_data, [&digital_buttons, &combos](gem_btn btn, pad_button pad_btn, u16 /*value*/, bool pressed, bool& /*abort*/)
{
if (!pressed)
return;
if (is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_5)) switch (btn)
digital_buttons |= CELL_GEM_CTRL_SQUARE; {
case gem_btn::start:
case gem_btn::select:
case gem_btn::square:
case gem_btn::cross:
case gem_btn::circle:
case gem_btn::triangle:
case gem_btn::move:
case gem_btn::t:
// Ignore this gem_btn if the same pad_button was already used in a combo
if (!combos.contains(pad_btn))
{
digital_buttons |= ::at32(btn_map, btn);
}
break;
default:
break;
}
});
if (is_pressed(CELL_MOUSE_BUTTON_1)) analog_t = (digital_buttons & CELL_GEM_CTRL_T) ? 0xFFFF : 0;
digital_buttons |= CELL_GEM_CTRL_T;
if (is_pressed(CELL_MOUSE_BUTTON_2))
digital_buttons |= CELL_GEM_CTRL_MOVE;
if (is_pressed(CELL_MOUSE_BUTTON_4))
digital_buttons |= CELL_GEM_CTRL_CIRCLE;
if (is_pressed(CELL_MOUSE_BUTTON_5))
digital_buttons |= CELL_GEM_CTRL_CROSS;
analog_t = (mouse_data.buttons & CELL_MOUSE_BUTTON_1) ? 0xFFFF : 0;
return true; return true;
} }

View file

@ -161,7 +161,7 @@ void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/
} }
const auto& cfg = g_cfg_buzz.players[i]; const auto& cfg = g_cfg_buzz.players[i];
cfg->handle_input(pad, true, [&buf, &index](buzz_btn btn, u16 /*value*/, bool pressed) cfg->handle_input(pad, true, [&buf, &index](buzz_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;

View file

@ -147,7 +147,7 @@ void usb_device_ghltar::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint
} }
const auto& cfg = ::at32(g_cfg_ghltar.players, m_controller_index); const auto& cfg = ::at32(g_cfg_ghltar.players, m_controller_index);
cfg->handle_input(pad, true, [&buf](ghltar_btn btn, u16 value, bool pressed) cfg->handle_input(pad, true, [&buf](ghltar_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;

View file

@ -227,7 +227,7 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint,
return; return;
} }
const auto input_callback = [&gc](guncon3_btn btn, u16 value, bool pressed) const auto input_callback = [&gc](guncon3_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;

View file

@ -280,7 +280,7 @@ void usb_device_topshotelite::interrupt_transfer(u32 buf_size, u8* buf, u32 /*en
} }
bool up = false, right = false, down = false, left = false; bool up = false, right = false, down = false, left = false;
const auto input_callback = [&ts, &up, &down, &left, &right](topshotelite_btn btn, u16 value, bool pressed) const auto input_callback = [&ts, &up, &down, &left, &right](topshotelite_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;

View file

@ -308,7 +308,7 @@ void usb_device_topshotfearmaster::interrupt_transfer(u32 buf_size, u8* buf, u32
} }
bool up = false, right = false, down = false, left = false; bool up = false, right = false, down = false, left = false;
const auto input_callback = [&ts, &up, &down, &left, &right](topshotfearmaster_btn btn, u16 value, bool pressed) const auto input_callback = [&ts, &up, &down, &left, &right](topshotfearmaster_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;

View file

@ -159,7 +159,7 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo
return; return;
const auto& cfg = ::at32(g_cfg_turntable.players, m_controller_index); const auto& cfg = ::at32(g_cfg_turntable.players, m_controller_index);
cfg->handle_input(pad, true, [&buf](turntable_btn btn, u16 value, bool pressed) cfg->handle_input(pad, true, [&buf](turntable_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/)
{ {
if (!pressed) if (!pressed)
return; return;

View file

@ -88,7 +88,7 @@ public:
button_map.clear(); button_map.clear();
} }
void handle_input(std::shared_ptr<Pad> pad, bool press_only, const std::function<void(T, u16, bool)>& func) const void handle_input(std::shared_ptr<Pad> pad, bool press_only, const std::function<void(T, pad_button, u16, bool, bool&)>& func) const
{ {
if (!pad) if (!pad)
return; return;
@ -97,19 +97,25 @@ public:
{ {
if (button.m_pressed || !press_only) if (button.m_pressed || !press_only)
{ {
handle_input(func, button.m_offset, button.m_outKeyCode, button.m_value, button.m_pressed, true); if (handle_input(func, button.m_offset, button.m_outKeyCode, button.m_value, button.m_pressed, true))
{
return;
}
} }
} }
for (const AnalogStick& stick : pad->m_sticks) for (const AnalogStick& stick : pad->m_sticks)
{ {
handle_input(func, stick.m_offset, get_axis_keycode(stick.m_offset, stick.m_value), stick.m_value, true, true); if (handle_input(func, stick.m_offset, get_axis_keycode(stick.m_offset, stick.m_value), stick.m_value, true, true))
{
return;
}
} }
} }
void handle_input(const Mouse& mouse, const std::function<void(T, u16, bool)>& func) const void handle_input(const Mouse& mouse, const std::function<void(T, pad_button, u16, bool, bool&)>& func) const
{ {
for (int i = 0; i < 7; i++) for (int i = 0; i < 8; i++)
{ {
const MouseButtonCodes cell_code = get_mouse_button_code(i); const MouseButtonCodes cell_code = get_mouse_button_code(i);
if ((mouse.buttons & cell_code)) if ((mouse.buttons & cell_code))
@ -117,7 +123,11 @@ public:
const pad_button button = static_cast<pad_button>(static_cast<int>(pad_button::mouse_button_1) + i); const pad_button button = static_cast<pad_button>(static_cast<int>(pad_button::mouse_button_1) + i);
const u32 offset = pad_button_offset(button); const u32 offset = pad_button_offset(button);
const u32 keycode = pad_button_keycode(button); const u32 keycode = pad_button_keycode(button);
handle_input(func, offset, keycode, 255, true, true);
if (handle_input(func, offset, keycode, 255, true, true))
{
return;
}
} }
} }
} }
@ -163,10 +173,12 @@ protected:
return empty_set; return empty_set;
} }
void handle_input(const std::function<void(T, u16, bool)>& func, u32 offset, u32 keycode, u16 value, bool pressed, bool check_axis) const bool handle_input(const std::function<void(T, pad_button, u16, bool, bool&)>& func, u32 offset, u32 keycode, u16 value, bool pressed, bool check_axis) const
{ {
m_mutex.lock(); m_mutex.lock();
bool abort = false;
const auto& btns = find_button(offset, keycode); const auto& btns = find_button(offset, keycode);
if (btns.empty()) if (btns.empty())
{ {
@ -180,24 +192,26 @@ protected:
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y:
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y:
handle_input(func, offset, static_cast<u32>(axis_direction::both), value, pressed, false); abort = handle_input(func, offset, static_cast<u32>(axis_direction::both), value, pressed, false);
break; break;
default: default:
break; break;
} }
} }
return; return abort;
} }
for (const auto& btn : btns) for (const auto& btn : btns)
{ {
if (btn && func) if (btn && func)
{ {
func(btn->btn_id(), value, pressed); func(btn->btn_id(), btn->get(), value, pressed, abort);
if (abort) break;
} }
} }
m_mutex.unlock(); m_mutex.unlock();
return abort;
} }
}; };

View file

@ -4,7 +4,7 @@
#include <array> #include <array>
enum class gem_btn enum class gem_btn : u32
{ {
start, start,
select, select,
@ -17,6 +17,18 @@ enum class gem_btn
x_axis, x_axis,
y_axis, y_axis,
combo_begin,
combo = combo_begin,
combo_start,
combo_select,
combo_triangle,
combo_circle,
combo_cross,
combo_square,
combo_move,
combo_t,
combo_end = combo_t,
count count
}; };
@ -41,6 +53,34 @@ struct cfg_fake_gems final : public emulated_pads_config<cfg_fake_gem, 4>
cfg_fake_gems() : emulated_pads_config<cfg_fake_gem, 4>("gem") {}; cfg_fake_gems() : emulated_pads_config<cfg_fake_gem, 4>("gem") {};
}; };
struct cfg_mouse_gem final : public emulated_pad_config<gem_btn>
{
cfg_mouse_gem(node* owner, const std::string& name) : emulated_pad_config(owner, name) {}
cfg_pad_btn<gem_btn> start{ this, "Start", gem_btn::start, pad_button::mouse_button_6 };
cfg_pad_btn<gem_btn> select{ this, "Select", gem_btn::select, pad_button::mouse_button_7 };
cfg_pad_btn<gem_btn> triangle{ this, "Triangle", gem_btn::triangle, pad_button::mouse_button_8 };
cfg_pad_btn<gem_btn> circle{ this, "Circle", gem_btn::circle, pad_button::mouse_button_4 };
cfg_pad_btn<gem_btn> cross{ this, "Cross", gem_btn::cross, pad_button::mouse_button_5 };
cfg_pad_btn<gem_btn> square{ this, "Square", gem_btn::square, pad_button::mouse_button_3 };
cfg_pad_btn<gem_btn> move{ this, "Move", gem_btn::move, pad_button::mouse_button_2 };
cfg_pad_btn<gem_btn> t{ this, "T", gem_btn::t, pad_button::mouse_button_1 };
cfg_pad_btn<gem_btn> combo{ this, "Combo", gem_btn::combo, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_start{ this, "Combo Start", gem_btn::combo_start, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_select{ this, "Combo Select", gem_btn::combo_select, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_triangle{ this, "Combo Triangle", gem_btn::combo_triangle, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_circle{ this, "Combo Circle", gem_btn::combo_circle, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_cross{ this, "Combo Cross", gem_btn::combo_cross, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_square{ this, "Combo Square", gem_btn::combo_square, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_move{ this, "Combo Move", gem_btn::combo_move, pad_button::pad_button_max_enum };
cfg_pad_btn<gem_btn> combo_t{ this, "Combo T", gem_btn::combo_t, pad_button::pad_button_max_enum };
};
struct cfg_mouse_gems final : public emulated_pads_config<cfg_mouse_gem, 4>
{
cfg_mouse_gems() : emulated_pads_config<cfg_mouse_gem, 4>("gem_mouse") {};
};
struct cfg_gem final : public emulated_pad_config<gem_btn> struct cfg_gem final : public emulated_pad_config<gem_btn>
{ {
cfg_gem(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} cfg_gem(node* owner, const std::string& name) : emulated_pad_config(owner, name) {}
@ -62,3 +102,4 @@ struct cfg_gems final : public emulated_pads_config<cfg_gem, 4>
extern cfg_gems g_cfg_gem_real; extern cfg_gems g_cfg_gem_real;
extern cfg_fake_gems g_cfg_gem_fake; extern cfg_fake_gems g_cfg_gem_fake;
extern cfg_mouse_gems g_cfg_gem_mouse;

View file

@ -203,7 +203,7 @@ void usb_device_usio::translate_input_taiko()
if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed())
{ {
const auto& cfg = ::at32(g_cfg_usio.players, pad_number); const auto& cfg = ::at32(g_cfg_usio.players, pad_number);
cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/)
{ {
switch (btn) switch (btn)
{ {
@ -288,7 +288,7 @@ void usb_device_usio::translate_input_tekken()
if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed())
{ {
const auto& cfg = ::at32(g_cfg_usio.players, pad_number); const auto& cfg = ::at32(g_cfg_usio.players, pad_number);
cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/)
{ {
switch (btn) switch (btn)
{ {

View file

@ -92,6 +92,10 @@ emulated_pad_settings_dialog::emulated_pad_settings_dialog(pad_type type, QWidge
setWindowTitle(tr("Configure Emulated PS Move (Fake)")); setWindowTitle(tr("Configure Emulated PS Move (Fake)"));
add_tabs<gem_btn>(tabs); add_tabs<gem_btn>(tabs);
break; break;
case emulated_pad_settings_dialog::pad_type::mousegem:
setWindowTitle(tr("Configure Emulated PS Move (Mouse)"));
add_tabs<gem_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::guncon3: case emulated_pad_settings_dialog::pad_type::guncon3:
setWindowTitle(tr("Configure Emulated GunCon 3")); setWindowTitle(tr("Configure Emulated GunCon 3"));
add_tabs<guncon3_btn>(tabs); add_tabs<guncon3_btn>(tabs);
@ -116,8 +120,12 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
{ {
ensure(!!tabs); ensure(!!tabs);
constexpr u32 max_items_per_column = 6; std::set<int> ignored_values;
int count = static_cast<int>(T::count);
const auto remove_value = [&ignored_values](int value)
{
ignored_values.insert(static_cast<int>(value));
};
usz players = 0; usz players = 0;
switch (m_type) switch (m_type)
@ -137,13 +145,29 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
case pad_type::gem: case pad_type::gem:
players = g_cfg_gem_real.players.size(); players = g_cfg_gem_real.players.size();
// Ignore x and y axis // Ignore combo, x and y axis
static_assert(static_cast<int>(gem_btn::y_axis) == static_cast<int>(gem_btn::count) - 1); remove_value(static_cast<int>(gem_btn::x_axis));
static_assert(static_cast<int>(gem_btn::x_axis) == static_cast<int>(gem_btn::count) - 2); remove_value(static_cast<int>(gem_btn::y_axis));
count -= 2; for (int i = static_cast<int>(gem_btn::combo_begin); i <= static_cast<int>(gem_btn::combo_end); i++)
{
remove_value(i);
}
break; break;
case pad_type::ds3gem: case pad_type::ds3gem:
players = g_cfg_gem_fake.players.size(); players = g_cfg_gem_fake.players.size();
// Ignore combo
for (int i = static_cast<int>(gem_btn::combo_begin); i <= static_cast<int>(gem_btn::combo_end); i++)
{
remove_value(i);
}
break;
case pad_type::mousegem:
players = g_cfg_gem_mouse.players.size();
// Ignore x and y axis
remove_value(static_cast<int>(gem_btn::x_axis));
remove_value(static_cast<int>(gem_btn::y_axis));
break; break;
case pad_type::guncon3: case pad_type::guncon3:
players = g_cfg_guncon3.players.size(); players = g_cfg_guncon3.players.size();
@ -156,6 +180,8 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
break; break;
} }
constexpr u32 max_items_per_column = 6;
const int count = static_cast<int>(T::count) - static_cast<int>(ignored_values.size());
int rows = count; int rows = count;
for (u32 cols = 1; utils::aligned_div(static_cast<u32>(count), cols) > max_items_per_column;) for (u32 cols = 1; utils::aligned_div(static_cast<u32>(count), cols) > max_items_per_column;)
@ -170,8 +196,10 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
QWidget* widget = new QWidget(this); QWidget* widget = new QWidget(this);
QGridLayout* grid_layout = new QGridLayout(this); QGridLayout* grid_layout = new QGridLayout(this);
for (int i = 0, row = 0, col = 0; i < count; i++, row++) for (int i = 0, row = 0, col = 0; i < static_cast<int>(T::count); i++)
{ {
if (ignored_values.contains(i)) continue;
const T id = static_cast<T>(i); const T id = static_cast<T>(i);
const QString name = QString::fromStdString(fmt::format("%s", id)); const QString name = QString::fromStdString(fmt::format("%s", id));
@ -179,16 +207,35 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
QGroupBox* gb = new QGroupBox(name, this); QGroupBox* gb = new QGroupBox(name, this);
QComboBox* combo = new QComboBox; QComboBox* combo = new QComboBox;
for (int p = 0; p < static_cast<int>(pad_button::pad_button_max_enum); p++) if constexpr (std::is_same_v<T, gem_btn>)
{ {
const QString translated = localized_emu::translated_pad_button(static_cast<pad_button>(p)); const gem_btn btn = static_cast<gem_btn>(i);
combo->addItem(translated); if (btn >= gem_btn::combo_begin && btn <= gem_btn::combo_end)
const int index = combo->findText(translated); {
combo->setItemData(index, p, button_role::button); gb->setToolTip(tr("Press the \"Combo\" button in combination with any of the other combo buttons to trigger their related PS Move button.\n"
combo->setItemData(index, i, button_role::emulated_button); "This can be useful if your device does not have enough regular buttons."));
}
} }
if constexpr (std::is_same_v<T, guncon3_btn> || std::is_same_v<T, topshotelite_btn> || std::is_same_v<T, topshotfearmaster_btn>) // Add empty value
combo->addItem("");
const int index = combo->findText("");
combo->setItemData(index, static_cast<int>(pad_button::pad_button_max_enum), button_role::button);
combo->setItemData(index, i, button_role::emulated_button);
if (m_type != pad_type::mousegem)
{
for (int p = 0; p < static_cast<int>(pad_button::pad_button_max_enum); p++)
{
const QString translated = localized_emu::translated_pad_button(static_cast<pad_button>(p));
combo->addItem(translated);
const int index = combo->findText(translated);
combo->setItemData(index, p, button_role::button);
combo->setItemData(index, i, button_role::emulated_button);
}
}
if (std::is_same_v<T, guncon3_btn> || std::is_same_v<T, topshotelite_btn> || std::is_same_v<T, topshotfearmaster_btn> || m_type == pad_type::mousegem)
{ {
for (int p = static_cast<int>(pad_button::mouse_button_1); p <= static_cast<int>(pad_button::mouse_button_8); p++) for (int p = static_cast<int>(pad_button::mouse_button_1); p <= static_cast<int>(pad_button::mouse_button_8); p++)
{ {
@ -221,6 +268,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
case pad_type::ds3gem: case pad_type::ds3gem:
saved_btn_id = ::at32(g_cfg_gem_fake.players, player)->get_pad_button(static_cast<gem_btn>(id)); saved_btn_id = ::at32(g_cfg_gem_fake.players, player)->get_pad_button(static_cast<gem_btn>(id));
break; break;
case pad_type::mousegem:
saved_btn_id = ::at32(g_cfg_gem_mouse.players, player)->get_pad_button(static_cast<gem_btn>(id));
break;
case pad_type::guncon3: case pad_type::guncon3:
saved_btn_id = ::at32(g_cfg_guncon3.players, player)->get_pad_button(static_cast<guncon3_btn>(id)); saved_btn_id = ::at32(g_cfg_guncon3.players, player)->get_pad_button(static_cast<guncon3_btn>(id));
break; break;
@ -265,6 +315,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
case pad_type::ds3gem: case pad_type::ds3gem:
::at32(g_cfg_gem_fake.players, player)->set_button(static_cast<gem_btn>(id), btn_id); ::at32(g_cfg_gem_fake.players, player)->set_button(static_cast<gem_btn>(id), btn_id);
break; break;
case pad_type::mousegem:
::at32(g_cfg_gem_mouse.players, player)->set_button(static_cast<gem_btn>(id), btn_id);
break;
case pad_type::guncon3: case pad_type::guncon3:
::at32(g_cfg_guncon3.players, player)->set_button(static_cast<guncon3_btn>(id), btn_id); ::at32(g_cfg_guncon3.players, player)->set_button(static_cast<guncon3_btn>(id), btn_id);
break; break;
@ -287,6 +340,8 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
h_layout->addWidget(combo); h_layout->addWidget(combo);
gb->setLayout(h_layout); gb->setLayout(h_layout);
grid_layout->addWidget(gb, row, col); grid_layout->addWidget(gb, row, col);
row++;
} }
widget->setLayout(grid_layout); widget->setLayout(grid_layout);
@ -334,6 +389,12 @@ void emulated_pad_settings_dialog::load_config()
cfg_log.notice("Could not load fake gem config. Using defaults."); cfg_log.notice("Could not load fake gem config. Using defaults.");
} }
break; break;
case emulated_pad_settings_dialog::pad_type::mousegem:
if (!g_cfg_gem_mouse.load())
{
cfg_log.notice("Could not load mouse gem config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::guncon3: case emulated_pad_settings_dialog::pad_type::guncon3:
if (!g_cfg_guncon3.load()) if (!g_cfg_guncon3.load())
{ {
@ -377,6 +438,9 @@ void emulated_pad_settings_dialog::save_config()
case emulated_pad_settings_dialog::pad_type::ds3gem: case emulated_pad_settings_dialog::pad_type::ds3gem:
g_cfg_gem_fake.save(); g_cfg_gem_fake.save();
break; break;
case emulated_pad_settings_dialog::pad_type::mousegem:
g_cfg_gem_mouse.save();
break;
case emulated_pad_settings_dialog::pad_type::guncon3: case emulated_pad_settings_dialog::pad_type::guncon3:
g_cfg_guncon3.save(); g_cfg_guncon3.save();
break; break;
@ -411,6 +475,9 @@ void emulated_pad_settings_dialog::reset_config()
case emulated_pad_settings_dialog::pad_type::ds3gem: case emulated_pad_settings_dialog::pad_type::ds3gem:
g_cfg_gem_fake.from_default(); g_cfg_gem_fake.from_default();
break; break;
case emulated_pad_settings_dialog::pad_type::mousegem:
g_cfg_gem_mouse.from_default();
break;
case emulated_pad_settings_dialog::pad_type::guncon3: case emulated_pad_settings_dialog::pad_type::guncon3:
g_cfg_guncon3.from_default(); g_cfg_guncon3.from_default();
break; break;
@ -454,6 +521,9 @@ void emulated_pad_settings_dialog::reset_config()
case pad_type::ds3gem: case pad_type::ds3gem:
def_btn_id = ::at32(g_cfg_gem_fake.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt())); def_btn_id = ::at32(g_cfg_gem_fake.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt()));
break; break;
case pad_type::mousegem:
def_btn_id = ::at32(g_cfg_gem_mouse.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt()));
break;
case pad_type::guncon3: case pad_type::guncon3:
def_btn_id = ::at32(g_cfg_guncon3.players, player)->default_pad_button(static_cast<guncon3_btn>(data.toInt())); def_btn_id = ::at32(g_cfg_guncon3.players, player)->default_pad_button(static_cast<guncon3_btn>(data.toInt()));
break; break;

View file

@ -21,6 +21,7 @@ public:
usio, usio,
gem, gem,
ds3gem, ds3gem,
mousegem,
guncon3, guncon3,
topshotelite, topshotelite,
topshotfearmaster, topshotfearmaster,

View file

@ -2911,6 +2911,12 @@ void main_window::CreateConnects()
dlg->show(); dlg->show();
}); });
connect(ui->confPSMoveMouseAct, &QAction::triggered, this, [this]
{
emulated_pad_settings_dialog* dlg = new emulated_pad_settings_dialog(emulated_pad_settings_dialog::pad_type::mousegem, this);
dlg->show();
});
connect(ui->confPSMoveDS3Act, &QAction::triggered, this, [this] connect(ui->confPSMoveDS3Act, &QAction::triggered, this, [this]
{ {
emulated_pad_settings_dialog* dlg = new emulated_pad_settings_dialog(emulated_pad_settings_dialog::pad_type::ds3gem, this); emulated_pad_settings_dialog* dlg = new emulated_pad_settings_dialog(emulated_pad_settings_dialog::pad_type::ds3gem, this);

View file

@ -244,6 +244,7 @@
<addaction name="confUSIOAct"/> <addaction name="confUSIOAct"/>
<addaction name="confPSMoveAct"/> <addaction name="confPSMoveAct"/>
<addaction name="confPSMoveDS3Act"/> <addaction name="confPSMoveDS3Act"/>
<addaction name="confPSMoveMouseAct"/>
<addaction name="confGunCon3Act"/> <addaction name="confGunCon3Act"/>
<addaction name="confTopShotEliteAct"/> <addaction name="confTopShotEliteAct"/>
<addaction name="confTopShotFearmasterAct"/> <addaction name="confTopShotFearmasterAct"/>
@ -1333,6 +1334,11 @@
<string>PS Move (Fake)</string> <string>PS Move (Fake)</string>
</property> </property>
</action> </action>
<action name="confPSMoveMouseAct">
<property name="text">
<string>PS Move (Mouse)</string>
</property>
</action>
<action name="confGunCon3Act"> <action name="confGunCon3Act">
<property name="text"> <property name="text">
<string>GunCon 3</string> <string>GunCon 3</string>