diff --git a/rpcs3/keyboard_pad_handler.cpp b/rpcs3/keyboard_pad_handler.cpp index 6f8e9ddf13..6762b8f4b1 100644 --- a/rpcs3/keyboard_pad_handler.cpp +++ b/rpcs3/keyboard_pad_handler.cpp @@ -8,6 +8,11 @@ constexpr auto qstr = QString::fromStdString; bool keyboard_pad_handler::Init() { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + m_last_mouse_move_left = now; + m_last_mouse_move_right = now; + m_last_mouse_move_up = now; + m_last_mouse_move_down = now; return true; } @@ -75,11 +80,13 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) bool is_max = pad->m_sticks[i].m_keyCodeMax == code; bool is_min = pad->m_sticks[i].m_keyCodeMin == code; + u16 normalized_value = std::max(u16(1), static_cast(std::floor((double)value / 2.0))); + if (is_max) - m_stick_max[i] = pressed ? 255 : 128; + m_stick_max[i] = pressed ? 128 + normalized_value : 128; if (is_min) - m_stick_min[i] = pressed ? 128 : 0; + m_stick_min[i] = pressed ? normalized_value : 0; if (is_max || is_min) pad->m_sticks[i].m_value = m_stick_max[i] - m_stick_min[i]; @@ -136,6 +143,9 @@ bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev) case QEvent::MouseButtonRelease: mouseReleaseEvent(static_cast(ev)); break; + case QEvent::MouseMove: + mouseMoveEvent(static_cast(ev)); + break; default: break; } @@ -221,6 +231,54 @@ void keyboard_pad_handler::processKeyEvent(QKeyEvent* event, bool pressed) void keyboard_pad_handler::keyPressEvent(QKeyEvent* event) { + if (event->modifiers() & Qt::AltModifier) + { + switch (event->key()) + { + case Qt::Key_I: + m_deadzone_y = std::min(m_deadzone_y + 1, 255); + LOG_SUCCESS(GENERAL, "mouse move adjustment: deadzone y = %d", m_deadzone_y); + event->ignore(); + return; + case Qt::Key_U: + m_deadzone_y = std::max(0, m_deadzone_y - 1); + LOG_SUCCESS(GENERAL, "mouse move adjustment: deadzone y = %d", m_deadzone_y); + event->ignore(); + return; + case Qt::Key_Z: + m_deadzone_x = std::min(m_deadzone_x + 1, 255); + LOG_SUCCESS(GENERAL, "mouse move adjustment: deadzone x = %d", m_deadzone_x); + event->ignore(); + return; + case Qt::Key_T: + m_deadzone_x = std::max(0, m_deadzone_x - 1); + LOG_SUCCESS(GENERAL, "mouse move adjustment: deadzone x = %d", m_deadzone_x); + event->ignore(); + return; + case Qt::Key_K: + m_multi_y = std::min(m_multi_y + 0.1, 5.0); + LOG_SUCCESS(GENERAL, "mouse move adjustment: multiplier y = %.2f", m_multi_y); + event->ignore(); + return; + case Qt::Key_J: + m_multi_y = std::max(0.0, m_multi_y - 0.1); + LOG_SUCCESS(GENERAL, "mouse move adjustment: multiplier y = %.2f", m_multi_y); + event->ignore(); + return; + case Qt::Key_H: + m_multi_x = std::min(m_multi_x + 0.1, 5.0); + LOG_SUCCESS(GENERAL, "mouse move adjustment: multiplier x = %.2f", m_multi_x); + event->ignore(); + return; + case Qt::Key_G: + m_multi_x = std::max(0.0, m_multi_x - 0.1); + LOG_SUCCESS(GENERAL, "mouse move adjustment: multiplier x = %.2f", m_multi_x); + event->ignore(); + return; + default: + break; + } + } processKeyEvent(event, 1); } @@ -241,6 +299,63 @@ void keyboard_pad_handler::mouseReleaseEvent(QMouseEvent* event) event->ignore(); } +void keyboard_pad_handler::mouseMoveEvent(QMouseEvent* event) +{ + static int movement_x = 0; + static int movement_y = 0; + static int last_pos_x = 0; + static int last_pos_y = 0; + + if (m_target && m_target->visibility() == QWindow::Visibility::FullScreen) + { + QPoint p_delta = m_target->geometry().topLeft() + QPoint(m_target->width() / 2, m_target->height() / 2); + QCursor::setPos(p_delta); + + movement_x = event->x() - p_delta.x(); + movement_y = event->y() - p_delta.y(); + } + else + { + movement_x = event->x() - last_pos_x; + movement_y = event->y() - last_pos_y; + + last_pos_x = event->x(); + last_pos_y = event->y(); + } + + movement_x = m_multi_x * (double)movement_x; + movement_y = m_multi_y * (double)movement_y; + + if (movement_x < 0) + { + Key(mouse::move_right, 0); + Key(mouse::move_left, 1, std::min(m_deadzone_x + std::abs(movement_x), 255)); + m_last_mouse_move_left = std::chrono::steady_clock::now(); + } + else if (movement_x > 0) + { + Key(mouse::move_left, 0); + Key(mouse::move_right, 1, std::min(m_deadzone_x + movement_x, 255)); + m_last_mouse_move_right = std::chrono::steady_clock::now(); + } + + // in Qt mouse up is equivalent to movement_y < 0 + if (movement_y < 0) + { + Key(mouse::move_down, 0); + Key(mouse::move_up, 1, std::min(m_deadzone_y + std::abs(movement_y), 255)); + m_last_mouse_move_up = std::chrono::steady_clock::now(); + } + else if (movement_y > 0) + { + Key(mouse::move_up, 0); + Key(mouse::move_down, 1, std::min(m_deadzone_y + movement_y, 255)); + m_last_mouse_move_down = std::chrono::steady_clock::now(); + } + + event->ignore(); +} + std::vector keyboard_pad_handler::ListDevices() { std::vector list_devices; @@ -454,5 +569,37 @@ void keyboard_pad_handler::ThreadProc() last_connection_status[i] = true; connected++; } + else + { + static std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + now = std::chrono::steady_clock::now(); + + double elapsed_left = std::chrono::duration_cast(now - m_last_mouse_move_left).count() / 1000.0; + double elapsed_right = std::chrono::duration_cast(now - m_last_mouse_move_right).count() / 1000.0; + double elapsed_up = std::chrono::duration_cast(now - m_last_mouse_move_up).count() / 1000.0; + double elapsed_down = std::chrono::duration_cast(now - m_last_mouse_move_down).count() / 1000.0; + + // roughly 1-2 frames to process the next mouse move + if (elapsed_left > 30.0) + { + Key(mouse::move_left, 0); + m_last_mouse_move_left = now; + } + if (elapsed_right > 30.0) + { + Key(mouse::move_right, 0); + m_last_mouse_move_right = now; + } + if (elapsed_up> 30.0) + { + Key(mouse::move_up, 0); + m_last_mouse_move_up = now; + } + if (elapsed_down > 30.0) + { + Key(mouse::move_down, 0); + m_last_mouse_move_down = now; + } + } } } diff --git a/rpcs3/keyboard_pad_handler.h b/rpcs3/keyboard_pad_handler.h index 9032692793..8ecbaf3c78 100644 --- a/rpcs3/keyboard_pad_handler.h +++ b/rpcs3/keyboard_pad_handler.h @@ -6,6 +6,14 @@ #include #include +enum mouse +{ + move_left = 0x05555550, + move_right = 0x05555551, + move_up = 0x05555552, + move_down = 0x05555553 +}; + class keyboard_pad_handler final : public QObject, public PadHandlerBase { // Unique button names for the config files and our pad settings dialog @@ -39,6 +47,11 @@ class keyboard_pad_handler final : public QObject, public PadHandlerBase { Qt::ExtraButton22 , "Mouse 22" }, { Qt::ExtraButton23 , "Mouse 23" }, { Qt::ExtraButton24 , "Mouse 24" }, + + { mouse::move_left , "Mouse MLeft" }, + { mouse::move_right , "Mouse MRight" }, + { mouse::move_up , "Mouse MUp" }, + { mouse::move_down , "Mouse MDown" }, }; public: @@ -52,6 +65,7 @@ public: void keyReleaseEvent(QKeyEvent* event); void mousePressEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); bool eventFilter(QObject* obj, QEvent* ev) override; @@ -77,4 +91,14 @@ private: std::vector> bindings; u8 m_stick_min[4] = { 0, 0, 0, 0 }; u8 m_stick_max[4] = { 128, 128, 128, 128 }; + + // Mouse Movements + std::chrono::steady_clock::time_point m_last_mouse_move_left; + std::chrono::steady_clock::time_point m_last_mouse_move_right; + std::chrono::steady_clock::time_point m_last_mouse_move_up; + std::chrono::steady_clock::time_point m_last_mouse_move_down; + int m_deadzone_x = 60; + int m_deadzone_y = 60; + double m_multi_x = 2; + double m_multi_y = 2.5; }; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 9f414ea3be..729eee93cc 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -456,6 +456,7 @@ void pad_settings_dialog::ReactivateButtons() if (m_padButtons->button(m_button_id)) { m_padButtons->button(m_button_id)->setPalette(m_palette); + m_padButtons->button(m_button_id)->releaseMouse(); } m_button_id = button_ids::id_pad_begin; @@ -528,7 +529,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) ReactivateButtons(); } -void pad_settings_dialog::mousePressEvent(QMouseEvent* event) +void pad_settings_dialog::mouseReleaseEvent(QMouseEvent* event) { if (m_handler->m_type != pad_handler::keyboard) { @@ -553,13 +554,67 @@ void pad_settings_dialog::mousePressEvent(QMouseEvent* event) ReactivateButtons(); } +void pad_settings_dialog::mouseMoveEvent(QMouseEvent* event) +{ + if (m_handler->m_type != pad_handler::keyboard) + { + return; + } + + if (m_button_id == button_ids::id_pad_begin) + { + return; + } + + if (m_button_id <= button_ids::id_pad_begin || m_button_id >= button_ids::id_pad_end) + { + LOG_NOTICE(HLE, "Pad Settings: Handler Type: %d, Unknown button ID: %d", static_cast(m_handler->m_type), m_button_id); + } + else + { + QPoint mouse_pos = QCursor::pos(); + int delta_x = mouse_pos.x() - m_last_pos.x(); + int delta_y = mouse_pos.y() - m_last_pos.y(); + + u32 key = 0; + + if (delta_x > 100) + { + key = mouse::move_right; + } + else if (delta_x < -100) + { + key = mouse::move_left; + } + else if (delta_y > 100) + { + key = mouse::move_down; + } + else if (delta_y < -100) + { + key = mouse::move_up; + } + + if (key != 0) + { + m_cfg_entries[m_button_id].key = ((keyboard_pad_handler*)m_handler.get())->GetMouseName(key); + m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key); + ReactivateButtons(); + } + } +} + bool pad_settings_dialog::eventFilter(QObject* object, QEvent* event) { // Disabled buttons should not absorb mouseclicks - if (event->type() == QEvent::MouseButtonPress) + if (event->type() == QEvent::MouseButtonRelease) { event->ignore(); } + if (event->type() == QEvent::MouseMove) + { + mouseMoveEvent((QMouseEvent*)event); + } return QDialog::eventFilter(object, event); } @@ -637,9 +692,12 @@ void pad_settings_dialog::OnPadButtonClicked(int id) ui->chooseHandler->setFocusPolicy(Qt::ClickFocus); ui->chooseDevice->setFocusPolicy(Qt::ClickFocus); + m_last_pos = QCursor::pos(); + m_button_id = id; m_padButtons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS)); m_padButtons->button(m_button_id)->setPalette(QPalette(Qt::blue)); + m_padButtons->button(m_button_id)->grabMouse(); SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons m_timer.start(1000); } diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 571267bdae..d5228430bb 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -122,6 +122,9 @@ private: int m_seconds = MAX_SECONDS; QTimer m_timer; + // Mouse Move + QPoint m_last_pos; + // Input timer. Its Callback handles the input QTimer m_timer_input; @@ -147,6 +150,7 @@ private: protected: /** Handle keyboard handler input */ void keyPressEvent(QKeyEvent *keyEvent) override; - void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; bool eventFilter(QObject* object, QEvent* event) override; };