Merge branch 'master' into rsx-volatile

This commit is contained in:
kd-11 2025-01-10 03:17:49 +03:00 committed by GitHub
commit 76d67498ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 419 additions and 96 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::move: return "Move";
case gem_btn::t: return "T";
case gem_btn::count: return "Count";
case gem_btn::x_axis: return "X-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;
@ -177,6 +186,7 @@ using gun_thread = named_thread<gun_handler>;
cfg_gems g_cfg_gem_real;
cfg_fake_gems g_cfg_gem_fake;
cfg_mouse_gems g_cfg_gem_mouse;
struct gem_config_data
{
@ -494,8 +504,14 @@ public:
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("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;
}
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)
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;
analog_t = std::max<u16>(analog_t, value);
break;
case gem_btn::x_axis:
case gem_btn::y_axis:
case gem_btn::count:
default:
break;
}
};
@ -1632,7 +1646,7 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>&
y_pos = 0;
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)
return;
@ -1828,41 +1842,97 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t<u16>& digital_buttons, be_t<u1
return false;
}
std::set<MouseButtonCodes> pressed_buttons;
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.
return (mouse_data.buttons & button) && (button == (CELL_MOUSE_BUTTON_3 + 0u/*fix warning*/) || pressed_buttons.insert(button).second);
{ gem_btn::start, CELL_GEM_CTRL_START },
{ 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))
digital_buttons |= CELL_GEM_CTRL_SELECT;
// Check combos
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))
digital_buttons |= CELL_GEM_CTRL_START;
switch (btn)
{
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))
digital_buttons |= CELL_GEM_CTRL_TRIANGLE;
// Check normal buttons
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))
digital_buttons |= CELL_GEM_CTRL_SQUARE;
switch (btn)
{
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))
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;
analog_t = (digital_buttons & CELL_GEM_CTRL_T) ? 0xFFFF : 0;
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];
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)
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);
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)
return;

View file

@ -227,7 +227,7 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint,
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)
return;

View file

@ -34,7 +34,7 @@ void MouseHandlerBase::save(utils::serial& ar)
bool MouseHandlerBase::is_time_for_update(double elapsed_time)
{
steady_clock::time_point now = steady_clock::now();
double elapsed = (now - last_update).count() / 1000'000.;
const double elapsed = (now - last_update).count() / 1000'000.;
if (elapsed > elapsed_time)
{

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;
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)
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;
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)
return;

View file

@ -159,7 +159,7 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo
return;
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)
return;

View file

@ -88,7 +88,7 @@ public:
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)
return;
@ -97,19 +97,25 @@ public:
{
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)
{
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);
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 u32 offset = pad_button_offset(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;
}
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();
bool abort = false;
const auto& btns = find_button(offset, keycode);
if (btns.empty())
{
@ -180,24 +192,26 @@ protected:
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y:
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
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;
default:
break;
}
}
return;
return abort;
}
for (const auto& btn : btns)
{
if (btn && func)
{
func(btn->btn_id(), value, pressed);
func(btn->btn_id(), btn->get(), value, pressed, abort);
if (abort) break;
}
}
m_mutex.unlock();
return abort;
}
};

View file

@ -4,7 +4,7 @@
#include <array>
enum class gem_btn
enum class gem_btn : u32
{
start,
select,
@ -17,6 +17,18 @@ enum class gem_btn
x_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
};
@ -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") {};
};
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>
{
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_fake_gems g_cfg_gem_fake;
extern cfg_mouse_gems g_cfg_gem_mouse;

View file

@ -39,7 +39,7 @@ void fmt_class_string<pad_button>::format(std::string& out, u64 arg)
case pad_button::rs_right: return "Right Stick Right";
case pad_button::rs_x: return "Right Stick X-Axis";
case pad_button::rs_y: return "Right Stick Y-Axis";
case pad_button::pad_button_max_enum: return "MAX_ENUM";
case pad_button::pad_button_max_enum: return "";
case pad_button::mouse_button_1: return "Mouse Button 1";
case pad_button::mouse_button_2: return "Mouse Button 2";
case pad_button::mouse_button_3: return "Mouse Button 3";

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())
{
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)
{
@ -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())
{
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)
{

View file

@ -265,7 +265,6 @@ namespace rsx
fade_animation.end = color4f(1.f);
fade_animation.active = true;
this->on_close = std::move(on_close);
visible = true;
const auto notify = std::make_shared<atomic_t<u32>>(0);

View file

@ -108,10 +108,10 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
switch (ev->type())
{
case QEvent::MouseButtonPress:
MouseButtonDown(static_cast<QMouseEvent*>(ev));
MouseButton(static_cast<QMouseEvent*>(ev), true);
break;
case QEvent::MouseButtonRelease:
MouseButtonUp(static_cast<QMouseEvent*>(ev));
MouseButton(static_cast<QMouseEvent*>(ev), false);
break;
case QEvent::MouseMove:
MouseMove(static_cast<QMouseEvent*>(ev));
@ -119,6 +119,12 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
case QEvent::Wheel:
MouseScroll(static_cast<QWheelEvent*>(ev));
break;
case QEvent::KeyPress:
Key(static_cast<QKeyEvent*>(ev), true);
break;
case QEvent::KeyRelease:
Key(static_cast<QKeyEvent*>(ev), false);
break;
default:
return false;
}
@ -126,22 +132,22 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
return false;
}
void basic_mouse_handler::MouseButtonDown(QMouseEvent* event)
void basic_mouse_handler::Key(QKeyEvent* event, bool pressed)
{
if (!event) [[unlikely]]
{
return;
}
const int button = event->button();
if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [button](const auto& entry){ return entry.second == button; });
const int key = event->key();
if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [key](const auto& entry){ return entry.second.code == key && entry.second.is_key; });
it != m_buttons.cend())
{
MouseHandlerBase::Button(0, it->first, true);
MouseHandlerBase::Button(0, it->first, pressed);
}
}
void basic_mouse_handler::MouseButtonUp(QMouseEvent* event)
void basic_mouse_handler::MouseButton(QMouseEvent* event, bool pressed)
{
if (!event) [[unlikely]]
{
@ -149,10 +155,10 @@ void basic_mouse_handler::MouseButtonUp(QMouseEvent* event)
}
const int button = event->button();
if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [button](const auto& entry){ return entry.second == button; });
if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [button](const auto& entry){ return entry.second.code == button && !entry.second.is_key; });
it != m_buttons.cend())
{
MouseHandlerBase::Button(0, it->first, false);
MouseHandlerBase::Button(0, it->first, pressed);
}
}
@ -176,17 +182,31 @@ bool basic_mouse_handler::get_mouse_lock_state() const
return false;
}
int basic_mouse_handler::get_mouse_button(const cfg::string& button)
basic_mouse_handler::mouse_button basic_mouse_handler::get_mouse_button(const cfg::string& button)
{
const std::string name = button.to_string();
const auto it = std::find_if(mouse_list.cbegin(), mouse_list.cend(), [&name](const auto& entry){ return entry.second == name; });
if (it != mouse_list.cend())
{
return it->first;
return mouse_button{
.code = static_cast<int>(it->first),
.is_key = false
};
}
return Qt::MouseButton::NoButton;
if (const u32 key = keyboard_pad_handler::GetKeyCode(QString::fromStdString(name)))
{
return mouse_button{
.code = static_cast<int>(key),
.is_key = true
};
}
return mouse_button{
.code = Qt::MouseButton::NoButton,
.is_key = false
};
}
void basic_mouse_handler::MouseMove(QMouseEvent* event)

View file

@ -20,8 +20,8 @@ public:
void Init(const u32 max_connect) override;
void SetTargetWindow(QWindow* target);
void MouseButtonDown(QMouseEvent* event);
void MouseButtonUp(QMouseEvent* event);
void Key(QKeyEvent* event, bool pressed);
void MouseButton(QMouseEvent* event, bool pressed);
void MouseScroll(QWheelEvent* event);
void MouseMove(QMouseEvent* event);
@ -29,8 +29,14 @@ public:
private:
void reload_config();
bool get_mouse_lock_state() const;
static int get_mouse_button(const cfg::string& button);
struct mouse_button
{
int code = Qt::MouseButton::NoButton;
bool is_key = false;
};
static mouse_button get_mouse_button(const cfg::string& button);
QWindow* m_target = nullptr;
std::map<u8, int> m_buttons;
std::map<u8, mouse_button> m_buttons;
};

View file

@ -2,6 +2,8 @@
#include "raw_mouse_config.h"
#include "Emu/Io/MouseHandler.h"
LOG_CHANNEL(cfg_log, "CFG");
std::string mouse_button_id(int code)
{
switch (code)

View file

@ -5,8 +5,6 @@
#include <array>
LOG_CHANNEL(cfg_log, "CFG");
std::string mouse_button_id(int code);
struct raw_mouse_config : cfg::node

View file

@ -190,6 +190,26 @@ void basic_mouse_settings_dialog::on_button_click(int id)
m_remap_timer.start(1000);
}
void basic_mouse_settings_dialog::keyPressEvent(QKeyEvent* event)
{
if (m_button_id < 0)
{
// We are not remapping a button, so pass the event to the base class.
QDialog::keyPressEvent(event);
return;
}
const std::string name = keyboard_pad_handler::GetKeyName(event, false);
g_cfg_mouse.get_button(m_button_id).from_string(name);
if (auto button = m_buttons->button(m_button_id))
{
button->setText(QString::fromStdString(name));
}
reactivate_buttons();
}
void basic_mouse_settings_dialog::mouseReleaseEvent(QMouseEvent* event)
{
if (m_button_id < 0)

View file

@ -39,6 +39,7 @@ private:
QTimer m_remap_timer;
protected:
void keyPressEvent(QKeyEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
bool eventFilter(QObject* object, QEvent* event) override;
};

View file

@ -1,6 +1,8 @@
#include "stdafx.h"
#include "emulated_pad_settings_dialog.h"
#include "localized_emu.h"
#include "Input/raw_mouse_config.h"
#include "Emu/Io/mouse_config.h"
#include "Emu/Io/buzz_config.h"
#include "Emu/Io/gem_config.h"
#include "Emu/Io/ghltar_config.h"
@ -13,6 +15,7 @@
#include <QDialogButtonBox>
#include <QGroupBox>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QVBoxLayout>
@ -92,6 +95,10 @@ emulated_pad_settings_dialog::emulated_pad_settings_dialog(pad_type type, QWidge
setWindowTitle(tr("Configure Emulated PS Move (Fake)"));
add_tabs<gem_btn>(tabs);
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:
setWindowTitle(tr("Configure Emulated GunCon 3"));
add_tabs<guncon3_btn>(tabs);
@ -116,8 +123,12 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
{
ensure(!!tabs);
constexpr u32 max_items_per_column = 6;
int count = static_cast<int>(T::count);
std::set<int> ignored_values;
const auto remove_value = [&ignored_values](int value)
{
ignored_values.insert(static_cast<int>(value));
};
usz players = 0;
switch (m_type)
@ -137,13 +148,29 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
case pad_type::gem:
players = g_cfg_gem_real.players.size();
// Ignore x and y axis
static_assert(static_cast<int>(gem_btn::y_axis) == static_cast<int>(gem_btn::count) - 1);
static_assert(static_cast<int>(gem_btn::x_axis) == static_cast<int>(gem_btn::count) - 2);
count -= 2;
// Ignore combo, x and y axis
remove_value(static_cast<int>(gem_btn::x_axis));
remove_value(static_cast<int>(gem_btn::y_axis));
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::ds3gem:
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;
case pad_type::guncon3:
players = g_cfg_guncon3.players.size();
@ -156,6 +183,8 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
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;
for (u32 cols = 1; utils::aligned_div(static_cast<u32>(count), cols) > max_items_per_column;)
@ -165,13 +194,30 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
m_combos.resize(players);
const bool show_mouse_legend = m_type == pad_type::mousegem;
if (show_mouse_legend)
{
if (!g_cfg_mouse.load())
{
cfg_log.notice("Could not restore mouse config. Using defaults.");
}
if (!g_cfg_raw_mouse.load())
{
cfg_log.notice("Could not restore raw mouse config. Using defaults.");
}
}
for (usz player = 0; player < players; player++)
{
QWidget* widget = new QWidget(this);
// Create grid with all buttons
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 QString name = QString::fromStdString(fmt::format("%s", id));
@ -179,16 +225,35 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
QGroupBox* gb = new QGroupBox(name, this);
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));
combo->addItem(translated);
const int index = combo->findText(translated);
combo->setItemData(index, p, button_role::button);
combo->setItemData(index, i, button_role::emulated_button);
const gem_btn btn = static_cast<gem_btn>(i);
if (btn >= gem_btn::combo_begin && btn <= gem_btn::combo_end)
{
gb->setToolTip(tr("Press the \"Combo\" button in combination with any of the other combo buttons to trigger their related PS Move button.\n"
"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++)
{
@ -221,6 +286,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
case pad_type::ds3gem:
saved_btn_id = ::at32(g_cfg_gem_fake.players, player)->get_pad_button(static_cast<gem_btn>(id));
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:
saved_btn_id = ::at32(g_cfg_guncon3.players, player)->get_pad_button(static_cast<guncon3_btn>(id));
break;
@ -265,6 +333,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
case pad_type::ds3gem:
::at32(g_cfg_gem_fake.players, player)->set_button(static_cast<gem_btn>(id), btn_id);
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:
::at32(g_cfg_guncon3.players, player)->set_button(static_cast<guncon3_btn>(id), btn_id);
break;
@ -287,9 +358,60 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
h_layout->addWidget(combo);
gb->setLayout(h_layout);
grid_layout->addWidget(gb, row, col);
row++;
}
widget->setLayout(grid_layout);
QVBoxLayout* v_layout = new QVBoxLayout(this);
// Create a legend of the current mouse settings
if (show_mouse_legend)
{
QHBoxLayout* legend_layout = new QHBoxLayout(this);
if (player == 0)
{
std::string basic_mouse_settings;
fmt::append(basic_mouse_settings, "1: %s\n", g_cfg_mouse.mouse_button_1.to_string());
fmt::append(basic_mouse_settings, "2: %s\n", g_cfg_mouse.mouse_button_2.to_string());
fmt::append(basic_mouse_settings, "3: %s\n", g_cfg_mouse.mouse_button_3.to_string());
fmt::append(basic_mouse_settings, "4: %s\n", g_cfg_mouse.mouse_button_4.to_string());
fmt::append(basic_mouse_settings, "5: %s\n", g_cfg_mouse.mouse_button_5.to_string());
fmt::append(basic_mouse_settings, "6: %s\n", g_cfg_mouse.mouse_button_6.to_string());
fmt::append(basic_mouse_settings, "7: %s\n", g_cfg_mouse.mouse_button_7.to_string());
fmt::append(basic_mouse_settings, "8: %s", g_cfg_mouse.mouse_button_8.to_string());
QGroupBox* gb_legend_basic = new QGroupBox(tr("Current Basic Mouse Config"), this);
QVBoxLayout* gb_legend_basic_layout = new QVBoxLayout(this);
gb_legend_basic_layout->addWidget(new QLabel(QString::fromStdString(basic_mouse_settings), this));
gb_legend_basic->setLayout(gb_legend_basic_layout);
legend_layout->addWidget(gb_legend_basic);
}
{
std::string raw_mouse_settings;
const auto& raw_cfg = *ensure(::at32(g_cfg_raw_mouse.players, player));
fmt::append(raw_mouse_settings, "1: %s\n", raw_cfg.mouse_button_1.to_string());
fmt::append(raw_mouse_settings, "2: %s\n", raw_cfg.mouse_button_2.to_string());
fmt::append(raw_mouse_settings, "3: %s\n", raw_cfg.mouse_button_3.to_string());
fmt::append(raw_mouse_settings, "4: %s\n", raw_cfg.mouse_button_4.to_string());
fmt::append(raw_mouse_settings, "5: %s\n", raw_cfg.mouse_button_5.to_string());
fmt::append(raw_mouse_settings, "6: %s\n", raw_cfg.mouse_button_6.to_string());
fmt::append(raw_mouse_settings, "7: %s\n", raw_cfg.mouse_button_7.to_string());
fmt::append(raw_mouse_settings, "8: %s", raw_cfg.mouse_button_8.to_string());
QGroupBox* gb_legend_raw = new QGroupBox(tr("Current Raw Mouse Config"), this);
QVBoxLayout* gb_legend_raw_layout = new QVBoxLayout(this);
gb_legend_raw_layout->addWidget(new QLabel(QString::fromStdString(raw_mouse_settings), this));
gb_legend_raw->setLayout(gb_legend_raw_layout);
legend_layout->addWidget(gb_legend_raw);
}
v_layout->addLayout(legend_layout);
}
v_layout->addLayout(grid_layout);
QWidget* widget = new QWidget(this);
widget->setLayout(v_layout);
tabs->addTab(widget, tr("Player %0").arg(player + 1));
}
}
@ -334,6 +456,12 @@ void emulated_pad_settings_dialog::load_config()
cfg_log.notice("Could not load fake gem config. Using defaults.");
}
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:
if (!g_cfg_guncon3.load())
{
@ -377,6 +505,9 @@ void emulated_pad_settings_dialog::save_config()
case emulated_pad_settings_dialog::pad_type::ds3gem:
g_cfg_gem_fake.save();
break;
case emulated_pad_settings_dialog::pad_type::mousegem:
g_cfg_gem_mouse.save();
break;
case emulated_pad_settings_dialog::pad_type::guncon3:
g_cfg_guncon3.save();
break;
@ -411,6 +542,9 @@ void emulated_pad_settings_dialog::reset_config()
case emulated_pad_settings_dialog::pad_type::ds3gem:
g_cfg_gem_fake.from_default();
break;
case emulated_pad_settings_dialog::pad_type::mousegem:
g_cfg_gem_mouse.from_default();
break;
case emulated_pad_settings_dialog::pad_type::guncon3:
g_cfg_guncon3.from_default();
break;
@ -454,6 +588,9 @@ void emulated_pad_settings_dialog::reset_config()
case pad_type::ds3gem:
def_btn_id = ::at32(g_cfg_gem_fake.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt()));
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:
def_btn_id = ::at32(g_cfg_guncon3.players, player)->default_pad_button(static_cast<guncon3_btn>(data.toInt()));
break;

View file

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

View file

@ -36,14 +36,14 @@ QString localized_emu::translated_pad_button(pad_button btn)
case pad_button::rs_x: return tr("Right Stick X-Axis");
case pad_button::rs_y: return tr("Right Stick Y-Axis");
case pad_button::pad_button_max_enum: return "";
case pad_button::mouse_button_1: return tr("Mouse Button 1");
case pad_button::mouse_button_2: return tr("Mouse Button 2");
case pad_button::mouse_button_3: return tr("Mouse Button 3");
case pad_button::mouse_button_4: return tr("Mouse Button 4");
case pad_button::mouse_button_5: return tr("Mouse Button 5");
case pad_button::mouse_button_6: return tr("Mouse Button 6");
case pad_button::mouse_button_7: return tr("Mouse Button 7");
case pad_button::mouse_button_8: return tr("Mouse Button 8");
case pad_button::mouse_button_1: return tr("Mouse 1");
case pad_button::mouse_button_2: return tr("Mouse 2");
case pad_button::mouse_button_3: return tr("Mouse 3");
case pad_button::mouse_button_4: return tr("Mouse 4");
case pad_button::mouse_button_5: return tr("Mouse 5");
case pad_button::mouse_button_6: return tr("Mouse 6");
case pad_button::mouse_button_7: return tr("Mouse 7");
case pad_button::mouse_button_8: return tr("Mouse 8");
}
return "";
}

View file

@ -2911,6 +2911,12 @@ void main_window::CreateConnects()
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]
{
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="confPSMoveAct"/>
<addaction name="confPSMoveDS3Act"/>
<addaction name="confPSMoveMouseAct"/>
<addaction name="confGunCon3Act"/>
<addaction name="confTopShotEliteAct"/>
<addaction name="confTopShotFearmasterAct"/>
@ -1333,6 +1334,11 @@
<string>PS Move (Fake)</string>
</property>
</action>
<action name="confPSMoveMouseAct">
<property name="text">
<string>PS Move (Mouse)</string>
</property>
</action>
<action name="confGunCon3Act">
<property name="text">
<string>GunCon 3</string>

View file

@ -11,6 +11,8 @@
#include <QMessageBox>
#include <QVBoxLayout>
LOG_CHANNEL(cfg_log, "CFG");
constexpr u32 button_count = 8;
raw_mouse_settings_dialog::raw_mouse_settings_dialog(QWidget* parent)