diff --git a/PCSX2_suite.sln b/PCSX2_suite.sln index b582d7d5a0..ad779c85e8 100644 --- a/PCSX2_suite.sln +++ b/PCSX2_suite.sln @@ -42,8 +42,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "3rdparty\xz\libl EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "3rdparty\fmt\fmt.vcxproj", "{449AD25E-424A-4714-BABC-68706CDCC33B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "3rdparty\libsamplerate\libsamplerate.vcxproj", "{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libchdr", "3rdparty\libchdr\libchdr.vcxproj", "{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpgd", "3rdparty\jpgd\jpgd.vcxproj", "{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}" @@ -248,18 +246,6 @@ Global {449AD25E-424A-4714-BABC-68706CDCC33B}.Release AVX2|x64.Build.0 = Release|x64 {449AD25E-424A-4714-BABC-68706CDCC33B}.Release|x64.ActiveCfg = Release|x64 {449AD25E-424A-4714-BABC-68706CDCC33B}.Release|x64.Build.0 = Release|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|x64.ActiveCfg = Debug|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug AVX2|x64.Build.0 = Debug|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|x64.ActiveCfg = Debug|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Debug|x64.Build.0 = Debug|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|x64.ActiveCfg = Devel|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel AVX2|x64.Build.0 = Devel|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|x64.ActiveCfg = Devel|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Devel|x64.Build.0 = Devel|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|x64.ActiveCfg = Release|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release AVX2|x64.Build.0 = Release|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.ActiveCfg = Release|x64 - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.Build.0 = Release|x64 {A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.ActiveCfg = Debug|x64 {A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.Build.0 = Debug|x64 {A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug|x64.ActiveCfg = Debug|x64 @@ -434,7 +420,6 @@ Global {27F17499-A372-4408-8AFA-4F9F4584FBD3} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {12728250-16EC-4DC6-94D7-E21DD88947F8} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {449AD25E-424A-4714-BABC-68706CDCC33B} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} - {47AFDBEF-F15F-4BC0-B436-5BE443C3F80F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} {C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38} diff --git a/pcsx2-gsrunner/Main.cpp b/pcsx2-gsrunner/Main.cpp index 90c5e8d524..5bfc57be4e 100644 --- a/pcsx2-gsrunner/Main.cpp +++ b/pcsx2-gsrunner/Main.cpp @@ -258,6 +258,10 @@ void Host::OnInputDeviceDisconnected(const std::string_view& identifier) { } +void Host::SetRelativeMouseMode(bool enabled) +{ +} + bool Host::AcquireHostDisplay(RenderAPI api, bool clear_state_on_fail) { const std::optional wi(GSRunner::GetPlatformWindowInfo()); @@ -772,4 +776,4 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return DefWindowProcW(hwnd, msg, wParam, lParam); } -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/pcsx2-qt/CMakeLists.txt b/pcsx2-qt/CMakeLists.txt index 9e3c5eae20..6bbe206307 100644 --- a/pcsx2-qt/CMakeLists.txt +++ b/pcsx2-qt/CMakeLists.txt @@ -117,6 +117,8 @@ target_sources(pcsx2-qt PRIVATE Settings/SettingsDialog.cpp Settings/SettingsDialog.h Settings/SettingsDialog.ui + Settings/USBBindingWidget_DrivingForce.ui + Settings/USBBindingWidget_GTForce.ui Tools/InputRecording/NewInputRecordingDlg.cpp Tools/InputRecording/NewInputRecordingDlg.h Tools/InputRecording/NewInputRecordingDlg.ui diff --git a/pcsx2-qt/DisplayWidget.cpp b/pcsx2-qt/DisplayWidget.cpp index 245ea728d4..8ca26267a3 100644 --- a/pcsx2-qt/DisplayWidget.cpp +++ b/pcsx2-qt/DisplayWidget.cpp @@ -84,17 +84,15 @@ std::optional DisplayWidget::getWindowInfo() return ret; } -void DisplayWidget::updateRelativeMode(bool master_enable) +void DisplayWidget::updateRelativeMode(bool enabled) { - bool relative_mode = master_enable && InputManager::HasPointerAxisBinds(); - #ifdef _WIN32 // prefer ClipCursor() over warping movement when we're using raw input - bool clip_cursor = relative_mode && false /*InputManager::IsUsingRawInput()*/; - if (m_relative_mouse_enabled == relative_mode && m_clip_mouse_enabled == clip_cursor) + bool clip_cursor = enabled && false /*InputManager::IsUsingRawInput()*/; + if (m_relative_mouse_enabled == enabled && m_clip_mouse_enabled == clip_cursor) return; - DevCon.WriteLn("updateRelativeMode(): relative=%s, clip=%s", relative_mode ? "yes" : "no", clip_cursor ? "yes" : "no"); + DevCon.WriteLn("updateRelativeMode(): relative=%s, clip=%s", enabled ? "yes" : "no", clip_cursor ? "yes" : "no"); if (!clip_cursor && m_clip_mouse_enabled) { @@ -102,13 +100,13 @@ void DisplayWidget::updateRelativeMode(bool master_enable) ClipCursor(nullptr); } #else - if (m_relative_mouse_enabled == relative_mode) + if (m_relative_mouse_enabled == enabled) return; - DevCon.WriteLn("updateRelativeMode(): relative=%s", relative_mode ? "yes" : "no"); + DevCon.WriteLn("updateRelativeMode(): relative=%s", enabled ? "yes" : "no"); #endif - if (relative_mode) + if (enabled) { #ifdef _WIN32 m_relative_mouse_enabled = !clip_cursor; @@ -129,21 +127,22 @@ void DisplayWidget::updateRelativeMode(bool master_enable) } -void DisplayWidget::updateCursor(bool master_enable) +void DisplayWidget::updateCursor(bool hidden) { -#ifdef _WIN32 - const bool hide = master_enable && (m_should_hide_cursor || m_relative_mouse_enabled || m_clip_mouse_enabled); -#else - const bool hide = master_enable && (m_should_hide_cursor || m_relative_mouse_enabled); -#endif - if (m_cursor_hidden == hide) + if (m_cursor_hidden == hidden) return; - m_cursor_hidden = hide; - if (hide) + m_cursor_hidden = hidden; + if (hidden) + { + DevCon.WriteLn("updateCursor(): Cursor is now hidden"); setCursor(Qt::BlankCursor); + } else + { + DevCon.WriteLn("updateCursor(): Cursor is now shown"); unsetCursor(); + } } void DisplayWidget::handleCloseEvent(QCloseEvent* event) diff --git a/pcsx2-qt/DisplayWidget.h b/pcsx2-qt/DisplayWidget.h index 76b14bcce7..2d943a7c84 100644 --- a/pcsx2-qt/DisplayWidget.h +++ b/pcsx2-qt/DisplayWidget.h @@ -32,15 +32,13 @@ public: QPaintEngine* paintEngine() const override; - __fi void setShouldHideCursor(bool hide) { m_should_hide_cursor = hide; } - int scaledWindowWidth() const; int scaledWindowHeight() const; std::optional getWindowInfo(); - void updateRelativeMode(bool master_enable); - void updateCursor(bool master_enable); + void updateRelativeMode(bool enabled); + void updateCursor(bool hidden); void handleCloseEvent(QCloseEvent* event); @@ -60,7 +58,6 @@ private: #ifdef _WIN32 bool m_clip_mouse_enabled = false; #endif - bool m_should_hide_cursor = false; bool m_cursor_hidden = false; std::vector m_keys_pressed_with_modifiers; diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index 5dadf59df3..662f4eeb19 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -409,6 +409,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread) connect(thread, &EmuThread::onUpdateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection); connect(thread, &EmuThread::onDestroyDisplayRequested, this, &MainWindow::destroyDisplay, Qt::BlockingQueuedConnection); connect(thread, &EmuThread::onResizeDisplayRequested, this, &MainWindow::displayResizeRequested); + connect(thread, &EmuThread::onRelativeMouseModeRequested, this, &MainWindow::relativeMouseModeRequested); connect(thread, &EmuThread::onVMStarting, this, &MainWindow::onVMStarting); connect(thread, &EmuThread::onVMStarted, this, &MainWindow::onVMStarted); connect(thread, &EmuThread::onVMPaused, this, &MainWindow::onVMPaused); @@ -1089,7 +1090,7 @@ bool MainWindow::isRenderingToMain() const bool MainWindow::shouldHideMouseCursor() const { - return isRenderingFullscreen() && Host::GetBoolSettingValue("UI", "HideMouseCursor", false); + return (isRenderingFullscreen() && Host::GetBoolSettingValue("UI", "HideMouseCursor", false)) || m_relative_mouse_mode; } bool MainWindow::shouldHideMainWindow() const @@ -1250,7 +1251,7 @@ void MainWindow::requestExit() void MainWindow::checkForSettingChanges() { if (m_display_widget) - m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused); + updateDisplayWidgetCursor(); updateWindowState(); } @@ -1802,10 +1803,7 @@ void MainWindow::onVMPaused() m_last_fps_status = m_status_verbose_widget->text(); m_status_verbose_widget->setText(tr("Paused")); if (m_display_widget) - { - m_display_widget->updateRelativeMode(false); - m_display_widget->updateCursor(false); - } + updateDisplayWidgetCursor(); } void MainWindow::onVMResumed() @@ -1824,8 +1822,7 @@ void MainWindow::onVMResumed() m_last_fps_status = QString(); if (m_display_widget) { - m_display_widget->updateRelativeMode(true); - m_display_widget->updateCursor(true); + updateDisplayWidgetCursor(); m_display_widget->setFocus(); } } @@ -1842,14 +1839,9 @@ void MainWindow::onVMStopped() updateInputRecordingActions(false); if (m_display_widget) - { - m_display_widget->updateRelativeMode(false); - m_display_widget->updateCursor(false); - } + updateDisplayWidgetCursor(); else - { switchToGameListView(); - } // reload played time if (m_game_list_widget->isShowingGameList()) @@ -2035,9 +2027,7 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main) m_ui.actionStartFullscreenUI->setEnabled(false); m_ui.actionStartFullscreenUI2->setEnabled(false); - m_display_widget->setShouldHideCursor(shouldHideMouseCursor()); - m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused); - m_display_widget->updateCursor(s_vm_valid && !s_vm_paused); + updateDisplayWidgetCursor(); m_display_widget->setFocus(); g_host_display->DoneCurrent(); @@ -2083,10 +2073,8 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b container->showNormal(); } + updateDisplayWidgetCursor(); m_display_widget->setFocus(); - m_display_widget->setShouldHideCursor(shouldHideMouseCursor()); - m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused); - m_display_widget->updateCursor(s_vm_valid && !s_vm_paused); updateWindowState(); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); @@ -2122,10 +2110,8 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b updateWindowTitle(); updateWindowState(); + updateDisplayWidgetCursor(); m_display_widget->setFocus(); - m_display_widget->setShouldHideCursor(shouldHideMouseCursor()); - m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused); - m_display_widget->updateCursor(s_vm_valid && !s_vm_paused); return m_display_widget; } @@ -2221,6 +2207,16 @@ void MainWindow::displayResizeRequested(qint32 width, qint32 height) QtUtils::ResizePotentiallyFixedSizeWindow(this, width, height + extra_height); } +void MainWindow::relativeMouseModeRequested(bool enabled) +{ + if (m_relative_mouse_mode == enabled) + return; + + m_relative_mouse_mode = enabled; + if (s_vm_valid && !s_vm_paused) + updateDisplayWidgetCursor(); +} + void MainWindow::destroyDisplay() { // Now we can safely destroy the display window. @@ -2284,6 +2280,12 @@ void MainWindow::destroyDisplayWidget(bool show_game_list) updateDisplayRelatedActions(false, false, false); } +void MainWindow::updateDisplayWidgetCursor() +{ + m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused && m_relative_mouse_mode); + m_display_widget->updateCursor(s_vm_valid && !s_vm_paused && shouldHideMouseCursor()); +} + void MainWindow::focusDisplayWidget() { if (!m_display_widget || centralWidget() != m_display_widget) diff --git a/pcsx2-qt/MainWindow.h b/pcsx2-qt/MainWindow.h index 23321810db..8d75adccc2 100644 --- a/pcsx2-qt/MainWindow.h +++ b/pcsx2-qt/MainWindow.h @@ -129,6 +129,7 @@ private Q_SLOTS: DisplayWidget* createDisplay(bool fullscreen, bool render_to_main); DisplayWidget* updateDisplay(bool fullscreen, bool render_to_main, bool surfaceless); void displayResizeRequested(qint32 width, qint32 height); + void relativeMouseModeRequested(bool enabled); void destroyDisplay(); void focusDisplayWidget(); @@ -231,6 +232,7 @@ private: void restoreDisplayWindowGeometryFromConfig(); void createDisplayWidget(bool fullscreen, bool render_to_main, bool is_exclusive_fullscreen); void destroyDisplayWidget(bool show_game_list); + void updateDisplayWidgetCursor(); void setDisplayFullscreen(const std::string& fullscreen_mode); SettingsDialog* getSettingsDialog(); @@ -283,6 +285,7 @@ private: quint32 m_current_game_crc; bool m_display_created = false; + bool m_relative_mouse_mode = false; bool m_save_states_invalidated = false; bool m_was_paused_on_surface_loss = false; bool m_was_disc_change_request = false; diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index de5da54118..10b3e84bc7 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -1486,6 +1486,11 @@ void Host::OnInputDeviceDisconnected(const std::string_view& identifier) emit g_emu_thread->onInputDeviceDisconnected(identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size())); } +void Host::SetRelativeMouseMode(bool enabled) +{ + emit g_emu_thread->onRelativeMouseModeRequested(enabled); +} + ////////////////////////////////////////////////////////////////////////// // Hotkeys ////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2-qt/QtHost.h b/pcsx2-qt/QtHost.h index d0bee4fee8..65b2885af6 100644 --- a/pcsx2-qt/QtHost.h +++ b/pcsx2-qt/QtHost.h @@ -120,6 +120,7 @@ Q_SIGNALS: DisplayWidget* onUpdateDisplayRequested(bool fullscreen, bool render_to_main, bool surfaceless); void onResizeDisplayRequested(qint32 width, qint32 height); void onDestroyDisplayRequested(); + void onRelativeMouseModeRequested(bool enabled); /// Called when the VM is starting initialization, but has not been completed yet. void onVMStarting(); diff --git a/pcsx2-qt/Settings/ControllerBindingWidgets.cpp b/pcsx2-qt/Settings/ControllerBindingWidgets.cpp index 92262f36b4..a711c65be2 100644 --- a/pcsx2-qt/Settings/ControllerBindingWidgets.cpp +++ b/pcsx2-qt/Settings/ControllerBindingWidgets.cpp @@ -15,10 +15,18 @@ #include "PrecompiledHeader.h" +#include #include #include #include +#include #include +#include "fmt/format.h" + +#include "common/StringUtil.h" + +#include "pcsx2/HostSettings.h" +#include "pcsx2/PAD/Host/PAD.h" #include "Settings/ControllerBindingWidgets.h" #include "Settings/ControllerSettingsDialog.h" @@ -28,9 +36,8 @@ #include "QtUtils.h" #include "SettingWidgetBinder.h" -#include "common/StringUtil.h" -#include "pcsx2/HostSettings.h" -#include "pcsx2/PAD/Host/PAD.h" +#include "ui_USBBindingWidget_DrivingForce.h" +#include "ui_USBBindingWidget_GTForce.h" ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port) : QWidget(parent) @@ -42,8 +49,8 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett populateControllerTypes(); onTypeChanged(); - ControllerSettingWidgetBinder::BindWidgetToInputProfileString(m_dialog->getProfileSettingsInterface(), - m_ui.controllerType, m_config_section, "Type", PAD::GetDefaultPadType(port)); + ControllerSettingWidgetBinder::BindWidgetToInputProfileString( + m_dialog->getProfileSettingsInterface(), m_ui.controllerType, m_config_section, "Type", PAD::GetDefaultPadType(port)); connect(m_ui.controllerType, QOverload::of(&QComboBox::currentIndexChanged), this, &ControllerBindingWidget::onTypeChanged); connect(m_ui.bindings, &QPushButton::clicked, this, &ControllerBindingWidget::onBindingsClicked); @@ -106,7 +113,10 @@ void ControllerBindingWidget::onTypeChanged() if (has_settings) { - m_settings_widget = new ControllerCustomSettingsWidget(this, m_ui.stackedWidget); + const QString settings_title(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name))); + const gsl::span settings(cinfo->settings, cinfo->num_settings); + m_settings_widget = new ControllerCustomSettingsWidget( + settings, m_config_section, std::string(), settings_title, cinfo->name, getDialog(), m_ui.stackedWidget); m_ui.stackedWidget->addWidget(m_settings_widget); } @@ -172,9 +182,7 @@ void ControllerBindingWidget::onAutomaticBindingClicked() // we set it as data, because the device list could get invalidated while the menu is up QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.first).arg(dev.second)); action->setData(dev.first); - connect(action, &QAction::triggered, this, [this, action]() { - doDeviceAutomaticBinding(action->data().toString()); - }); + connect(action, &QAction::triggered, this, [this, action]() { doDeviceAutomaticBinding(action->data().toString()); }); added = true; } @@ -266,8 +274,7 @@ ControllerMacroWidget::~ControllerMacroWidget() = default; void ControllerMacroWidget::updateListItem(u32 index) { - m_ui.portList->item(static_cast(index)) - ->setText(tr("Macro %1\n%2").arg(index + 1).arg(m_macros[index]->getSummary())); + m_ui.portList->item(static_cast(index))->setText(tr("Macro %1\n%2").arg(index + 1).arg(m_macros[index]->getSummary())); } void ControllerMacroWidget::createWidgets(ControllerBindingWidget* parent) @@ -291,8 +298,7 @@ void ControllerMacroWidget::createWidgets(ControllerBindingWidget* parent) ////////////////////////////////////////////////////////////////////////// -ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* parent, ControllerBindingWidget* bwidget, - u32 index) +ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* parent, ControllerBindingWidget* bwidget, u32 index) : QWidget(parent) , m_parent(parent) , m_bwidget(bwidget) @@ -310,8 +316,7 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare } // load binds (single string joined by &) - const std::string binds_string( - dialog->getStringValue(section.c_str(), fmt::format("Macro{}Binds", index + 1u).c_str(), "")); + const std::string binds_string(dialog->getStringValue(section.c_str(), fmt::format("Macro{}Binds", index + 1u).c_str(), "")); const std::vector buttons_split(StringUtil::SplitString(binds_string, '&', true)); for (const std::string_view& button : buttons_split) @@ -335,15 +340,15 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare QListWidgetItem* item = new QListWidgetItem(); item->setText(QString::fromUtf8(bi.display_name)); - item->setCheckState((std::find(m_binds.begin(), m_binds.end(), &bi) != m_binds.end()) ? Qt::Checked : - Qt::Unchecked); + item->setCheckState((std::find(m_binds.begin(), m_binds.end(), &bi) != m_binds.end()) ? Qt::Checked : Qt::Unchecked); m_ui.bindList->addItem(item); } m_frequency = dialog->getIntValue(section.c_str(), fmt::format("Macro{}Frequency", index + 1u).c_str(), 0); updateFrequencyText(); - m_ui.trigger->initialize(dialog->getProfileSettingsInterface(), section, fmt::format("Macro{}", index + 1u)); + m_ui.trigger->initialize( + dialog->getProfileSettingsInterface(), InputBindingInfo::Type::Macro, section, fmt::format("Macro{}", index + 1u)); connect(m_ui.increaseFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(1); }); connect(m_ui.decreateFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(-1); }); @@ -368,8 +373,8 @@ QString ControllerMacroEditWidget::getSummary() const void ControllerMacroEditWidget::onSetFrequencyClicked() { bool okay; - int new_freq = QInputDialog::getInt(this, tr("Set Frequency"), tr("Frequency: "), static_cast(m_frequency), 0, - std::numeric_limits::max(), 1, &okay); + int new_freq = QInputDialog::getInt( + this, tr("Set Frequency"), tr("Frequency: "), static_cast(m_frequency), 0, std::numeric_limits::max(), 1, &okay); if (!okay) return; @@ -388,9 +393,8 @@ void ControllerMacroEditWidget::modFrequency(s32 delta) void ControllerMacroEditWidget::updateFrequency() { - m_bwidget->getDialog()->setIntValue(m_bwidget->getConfigSection().c_str(), - fmt::format("Macro{}Frequency", m_index + 1u).c_str(), - static_cast(m_frequency)); + m_bwidget->getDialog()->setIntValue( + m_bwidget->getConfigSection().c_str(), fmt::format("Macro{}Frequency", m_index + 1u).c_str(), static_cast(m_frequency)); updateFrequencyText(); } @@ -453,17 +457,21 @@ void ControllerMacroEditWidget::updateBinds() ////////////////////////////////////////////////////////////////////////// -ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(ControllerBindingWidget* parent, QWidget* parent_widget) +ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span settings, std::string config_section, + std::string config_prefix, const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog, + QWidget* parent_widget) : QWidget(parent_widget) - , m_parent(parent) + , m_settings(settings) + , m_config_section(std::move(config_section)) + , m_config_prefix(std::move(config_prefix)) + , m_dialog(dialog) { - const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(parent->getControllerType()); - if (!cinfo || cinfo->num_settings == 0) + if (settings.empty()) return; - QGroupBox* gbox = new QGroupBox(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name)), this); + QGroupBox* gbox = new QGroupBox(group_title, this); QGridLayout* gbox_layout = new QGridLayout(gbox); - createSettingWidgets(parent, gbox, gbox_layout, cinfo); + createSettingWidgets(translation_ctx, gbox, gbox_layout); QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -481,26 +489,65 @@ ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(ControllerBinding ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() = default; -void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidget* parent, QWidget* widget_parent, - QGridLayout* layout, const PAD::ControllerInfo* cinfo) +static std::tuple getPrefixAndSuffixForIntFormat(const QString& format) { - const std::string& section = parent->getConfigSection(); - SettingsInterface* sif = parent->getDialog()->getProfileSettingsInterface(); + QString prefix, suffix; + QRegularExpression re(QStringLiteral("(.*)%.*d(.*)")); + QRegularExpressionMatch match(re.match(format)); + if (match.isValid()) + { + prefix = match.captured(1).replace(QStringLiteral("%%"), QStringLiteral("%")); + suffix = match.captured(2).replace(QStringLiteral("%%"), QStringLiteral("%")); + } + + return std::tie(prefix, suffix); +} + +static std::tuple getPrefixAndSuffixForFloatFormat(const QString& format) +{ + QString prefix, suffix; + int decimals = -1; + + QRegularExpression re(QStringLiteral("(.*)%.*([0-9]+)f(.*)")); + QRegularExpressionMatch match(re.match(format)); + if (match.isValid()) + { + prefix = match.captured(1).replace(QStringLiteral("%%"), QStringLiteral("%")); + suffix = match.captured(3).replace(QStringLiteral("%%"), QStringLiteral("%")); + + bool decimals_ok; + decimals = match.captured(2).toInt(&decimals_ok); + if (!decimals_ok) + decimals = -1; + } + else + { + re = QRegularExpression(QStringLiteral("(.*)%.*f(.*)")); + match = re.match(format); + prefix = match.captured(1).replace(QStringLiteral("%%"), QStringLiteral("%")); + suffix = match.captured(2).replace(QStringLiteral("%%"), QStringLiteral("%")); + } + + return std::tie(prefix, suffix, decimals); +} + +void ControllerCustomSettingsWidget::createSettingWidgets(const char* translation_ctx, QWidget* widget_parent, QGridLayout* layout) +{ + SettingsInterface* sif = m_dialog->getProfileSettingsInterface(); int current_row = 0; - for (u32 i = 0; i < cinfo->num_settings; i++) + for (const SettingInfo& si : m_settings) { - const SettingInfo& si = cinfo->settings[i]; - std::string key_name = si.name; + std::string key_name = m_config_prefix + si.name; switch (si.type) { case SettingInfo::Type::Boolean: { - QCheckBox* cb = new QCheckBox(qApp->translate(cinfo->name, si.display_name), widget_parent); + QCheckBox* cb = new QCheckBox(qApp->translate(translation_ctx, si.display_name), widget_parent); cb->setObjectName(QString::fromUtf8(si.name)); - ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, cb, section, std::move(key_name), - si.BooleanDefaultValue()); + ControllerSettingWidgetBinder::BindWidgetToInputProfileBool( + sif, cb, m_config_section, std::move(key_name), si.BooleanDefaultValue()); layout->addWidget(cb, current_row, 0, 1, 4); current_row++; } @@ -513,8 +560,14 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge sb->setMinimum(si.IntegerMinValue()); sb->setMaximum(si.IntegerMaxValue()); sb->setSingleStep(si.IntegerStepValue()); - SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, section, std::move(key_name), si.IntegerDefaultValue()); - layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), widget_parent), current_row, 0); + if (si.format) + { + const auto [prefix, suffix] = getPrefixAndSuffixForIntFormat(QString::fromUtf8(si.format)); + sb->setPrefix(prefix); + sb->setSuffix(suffix); + } + SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue()); + layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0); layout->addWidget(sb, current_row, 1, 1, 3); current_row++; } @@ -525,9 +578,10 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge QComboBox* cb = new QComboBox(widget_parent); cb->setObjectName(QString::fromUtf8(si.name)); for (u32 i = 0; si.options[i] != nullptr; i++) - cb->addItem(qApp->translate(cinfo->name, si.options[i])); - SettingWidgetBinder::BindWidgetToIntSetting(sif, cb, section, std::move(key_name), si.IntegerDefaultValue(), si.IntegerMinValue()); - layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), widget_parent), current_row, 0); + cb->addItem(qApp->translate(translation_ctx, si.options[i])); + SettingWidgetBinder::BindWidgetToIntSetting( + sif, cb, m_config_section, std::move(key_name), si.IntegerDefaultValue(), si.IntegerMinValue()); + layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0); layout->addWidget(cb, current_row, 1, 1, 3); current_row++; } @@ -540,8 +594,19 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge sb->setMinimum(si.FloatMinValue()); sb->setMaximum(si.FloatMaxValue()); sb->setSingleStep(si.FloatStepValue()); - SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, section, std::move(key_name), si.FloatDefaultValue()); - layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), widget_parent), current_row, 0); +#if 0 + // We can't use this until we handle multiplier. + if (si.format) + { + const auto [prefix, suffix, decimals] = getPrefixAndSuffixForFloatFormat(QString::fromUtf8(si.format)); + sb->setPrefix(prefix); + if (decimals >= 0) + sb->setDecimals(decimals); + sb->setSuffix(suffix); + } +#endif + SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue()); + layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0); layout->addWidget(sb, current_row, 1, 1, 3); current_row++; } @@ -551,8 +616,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge { QLineEdit* le = new QLineEdit(widget_parent); le->setObjectName(QString::fromUtf8(si.name)); - SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue()); - layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), widget_parent), current_row, 0); + SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue()); + layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0); layout->addWidget(le, current_row, 1, 1, 3); current_row++; } @@ -571,10 +636,10 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge else if (si.options) { for (u32 i = 0; si.options[i] != nullptr; i++) - cb->addItem(qApp->translate(cinfo->name, si.options[i])); + cb->addItem(qApp->translate(translation_ctx, si.options[i])); } - SettingWidgetBinder::BindWidgetToStringSetting(sif, cb, section, std::move(key_name), si.StringDefaultValue()); - layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), widget_parent), current_row, 0); + SettingWidgetBinder::BindWidgetToStringSetting(sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue()); + layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0); layout->addWidget(cb, current_row, 1, 1, 3); current_row++; } @@ -585,9 +650,9 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge QLineEdit* le = new QLineEdit(widget_parent); le->setObjectName(QString::fromUtf8(si.name)); QPushButton* browse_button = new QPushButton(tr("Browse..."), widget_parent); - SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue()); + SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue()); connect(browse_button, &QPushButton::clicked, [this, le]() { - QString path = QFileDialog::getOpenFileName(this, tr("Select File")); + const QString path(QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select File")))); if (!path.isEmpty()) le->setText(path); }); @@ -596,14 +661,14 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge hbox->addWidget(le, 1); hbox->addWidget(browse_button); - layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), widget_parent), current_row, 0); + layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0); layout->addLayout(hbox, current_row, 1, 1, 3); current_row++; } break; } - QLabel* label = new QLabel(si.description ? qApp->translate(cinfo->name, si.description) : QString(), widget_parent); + QLabel* label = new QLabel(si.description ? qApp->translate(translation_ctx, si.description) : QString(), widget_parent); label->setWordWrap(true); layout->addWidget(label, current_row++, 0, 1, 4); @@ -613,13 +678,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge void ControllerCustomSettingsWidget::restoreDefaults() { - const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(m_parent->getControllerType()); - if (!cinfo || cinfo->num_settings == 0) - return; - - for (u32 i = 0; i < cinfo->num_settings; i++) + for (const SettingInfo& si : m_settings) { - const SettingInfo& si = cinfo->settings[i]; const QString key(QString::fromStdString(si.name)); switch (si.type) @@ -664,6 +724,21 @@ void ControllerCustomSettingsWidget::restoreDefaults() } break; + case SettingInfo::Type::StringList: + { + QComboBox* widget = findChild(QString::fromStdString(si.name)); + if (widget) + { + const QString default_value(QString::fromUtf8(si.StringDefaultValue())); + int index = widget->findData(default_value); + if (index < 0) + index = widget->findText(default_value); + if (index >= 0) + widget->setCurrentIndex(index); + } + } + break; + case SettingInfo::Type::Path: { QLineEdit* widget = findChild(QString::fromStdString(si.name)); @@ -694,26 +769,32 @@ QIcon ControllerBindingWidget_Base::getIcon() const void ControllerBindingWidget_Base::initBindingWidgets() { - const std::string& type = getControllerType(); + const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(getControllerType()); + if (!cinfo) + return; + const std::string& config_section = getConfigSection(); - std::vector bindings(PAD::GetControllerBinds(type)); SettingsInterface* sif = getDialog()->getProfileSettingsInterface(); - for (std::string& binding : bindings) + for (u32 i = 0; i < cinfo->num_bindings; i++) { - InputBindingWidget* widget = findChild(QString::fromStdString(binding)); - if (!widget) + const InputBindingInfo& bi = cinfo->bindings[i]; + if (bi.bind_type == InputBindingInfo::Type::Axis || bi.bind_type == InputBindingInfo::Type::HalfAxis || + bi.bind_type == InputBindingInfo::Type::Button || bi.bind_type == InputBindingInfo::Type::Pointer || + bi.bind_type == InputBindingInfo::Type::Device) { - Console.Error("(ControllerBindingWidget_Base) No widget found for '%s' (%.*s)", - binding.c_str(), static_cast(type.size()), type.data()); - continue; - } + InputBindingWidget* widget = findChild(QString::fromStdString(bi.name)); + if (!widget) + { + Console.Error("(ControllerBindingWidget_Base) No widget found for '%s' (%s)", bi.name, cinfo->name); + continue; + } - widget->initialize(sif, config_section, std::move(binding)); + widget->initialize(sif, bi.bind_type, config_section, bi.name); + } } - const PAD::VibrationCapabilities vibe_caps = PAD::GetControllerVibrationCapabilities(type); - switch (vibe_caps) + switch (cinfo->vibration_caps) { case PAD::VibrationCapabilities::LargeSmallMotors: { @@ -763,3 +844,385 @@ ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance } ////////////////////////////////////////////////////////////////////////// + +USBDeviceWidget::USBDeviceWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port) + : QWidget(parent) + , m_dialog(dialog) + , m_config_section(StringUtil::StdStringFromFormat("USB%u", port + 1u)) + , m_port_number(port) +{ + m_ui.setupUi(this); + populateDeviceTypes(); + populatePages(); + + ControllerSettingWidgetBinder::BindWidgetToInputProfileString( + m_dialog->getProfileSettingsInterface(), m_ui.deviceType, m_config_section, "Type", "None"); + + connect(m_ui.deviceType, QOverload::of(&QComboBox::currentIndexChanged), this, &USBDeviceWidget::onTypeChanged); + connect(m_ui.deviceSubtype, QOverload::of(&QComboBox::currentIndexChanged), this, &USBDeviceWidget::onSubTypeChanged); + connect(m_ui.bindings, &QPushButton::clicked, this, &USBDeviceWidget::onBindingsClicked); + connect(m_ui.settings, &QPushButton::clicked, this, &USBDeviceWidget::onSettingsClicked); + connect(m_ui.automaticBinding, &QPushButton::clicked, this, &USBDeviceWidget::onAutomaticBindingClicked); + connect(m_ui.clearBindings, &QPushButton::clicked, this, &USBDeviceWidget::onClearBindingsClicked); +} + +USBDeviceWidget::~USBDeviceWidget() = default; + +QIcon USBDeviceWidget::getIcon() const +{ + return QIcon::fromTheme("usb-fill"); +} + +void USBDeviceWidget::populateDeviceTypes() +{ + m_ui.deviceType->addItem(qApp->translate("USB", USB::GetDeviceName("None")), QStringLiteral("None")); + for (const auto& [name, display_name] : USB::GetDeviceTypes()) + m_ui.deviceType->addItem(QString::fromStdString(display_name), QString::fromStdString(name)); +} + +void USBDeviceWidget::populatePages() +{ + m_device_type = m_dialog->getStringValue(m_config_section.c_str(), "Type", "None"); + m_device_subtype = m_dialog->getIntValue(m_config_section.c_str(), fmt::format("{}_subtype", m_device_type).c_str(), 0); + + { + QSignalBlocker sb(m_ui.deviceSubtype); + m_ui.deviceSubtype->clear(); + for (const std::string& subtype : USB::GetDeviceSubtypes(m_device_type)) + m_ui.deviceSubtype->addItem(qApp->translate("USB", subtype.c_str())); + m_ui.deviceSubtype->setCurrentIndex(m_device_subtype); + m_ui.deviceSubtype->setVisible(m_ui.deviceSubtype->count() > 0); + } + + if (m_bindings_widget) + { + m_ui.stackedWidget->removeWidget(m_bindings_widget); + delete m_bindings_widget; + m_bindings_widget = nullptr; + } + if (m_settings_widget) + { + m_ui.stackedWidget->removeWidget(m_settings_widget); + delete m_settings_widget; + m_settings_widget = nullptr; + } + + const gsl::span bindings(USB::GetDeviceBindings(m_device_type, m_device_subtype)); + const gsl::span settings(USB::GetDeviceSettings(m_device_type, m_device_subtype)); + m_ui.bindings->setEnabled(!bindings.empty()); + m_ui.settings->setEnabled(!settings.empty()); + + if (!bindings.empty()) + { + m_bindings_widget = USBBindingWidget::createInstance(m_device_type, m_device_subtype, bindings, this); + if (m_bindings_widget) + { + m_ui.stackedWidget->addWidget(m_bindings_widget); + m_ui.stackedWidget->setCurrentWidget(m_bindings_widget); + } + } + + if (!settings.empty()) + { + const QString settings_title(tr("Device Settings")); + m_settings_widget = new ControllerCustomSettingsWidget( + settings, m_config_section, m_device_type + "_", settings_title, m_device_type.c_str(), m_dialog, m_ui.stackedWidget); + m_ui.stackedWidget->addWidget(m_settings_widget); + } + + updateHeaderToolButtons(); +} + +void USBDeviceWidget::onTypeChanged() +{ + populatePages(); + m_dialog->updateListDescription(m_port_number, this); +} + +void USBDeviceWidget::onSubTypeChanged(int new_index) +{ + m_dialog->setIntValue(m_config_section.c_str(), fmt::format("{}_subtype", m_device_type).c_str(), new_index); + onTypeChanged(); +} + +void USBDeviceWidget::updateHeaderToolButtons() +{ + const QWidget* current_widget = m_ui.stackedWidget->currentWidget(); + const QSignalBlocker bindings_sb(m_ui.bindings); + const QSignalBlocker settings_sb(m_ui.settings); + + const bool is_bindings = (m_bindings_widget && current_widget == m_bindings_widget); + const bool is_settings = (m_settings_widget && current_widget == m_settings_widget); + m_ui.bindings->setChecked(is_bindings); + m_ui.automaticBinding->setEnabled(is_bindings); + m_ui.clearBindings->setEnabled(is_bindings); + m_ui.settings->setChecked(is_settings); +} + +void USBDeviceWidget::onBindingsClicked() +{ + if (!m_bindings_widget) + return; + + m_ui.stackedWidget->setCurrentWidget(m_bindings_widget); + updateHeaderToolButtons(); +} + +void USBDeviceWidget::onSettingsClicked() +{ + if (!m_settings_widget) + return; + + m_ui.stackedWidget->setCurrentWidget(m_settings_widget); + updateHeaderToolButtons(); +} + +void USBDeviceWidget::onAutomaticBindingClicked() +{ + QMenu menu(this); + bool added = false; + + for (const QPair& dev : m_dialog->getDeviceList()) + { + // we set it as data, because the device list could get invalidated while the menu is up + QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.first).arg(dev.second)); + action->setData(dev.first); + connect(action, &QAction::triggered, this, [this, action]() { doDeviceAutomaticBinding(action->data().toString()); }); + added = true; + } + + if (!added) + { + QAction* action = menu.addAction(tr("No devices available")); + action->setEnabled(false); + } + + menu.exec(QCursor::pos()); +} + +void USBDeviceWidget::onClearBindingsClicked() +{ + if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Clear Bindings"), + tr("Are you sure you want to clear all bindings for this controller? This action cannot be undone.")) != QMessageBox::Yes) + { + return; + } + + if (m_dialog->isEditingGlobalSettings()) + { + { + auto lock = Host::GetSettingsLock(); + USB::ClearPortBindings(*Host::Internal::GetBaseSettingsLayer(), m_port_number); + } + Host::CommitBaseSettingChanges(); + } + else + { + USB::ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number); + m_dialog->getProfileSettingsInterface()->Save(); + } + + // force a refresh after clearing + g_emu_thread->applySettings(); + onTypeChanged(); +} + +void USBDeviceWidget::doDeviceAutomaticBinding(const QString& device) +{ + std::vector> mapping = InputManager::GetGenericBindingMapping(device.toStdString()); + if (mapping.empty()) + { + QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Automatic Binding"), + tr("No generic bindings were generated for device '%1'. The controller/source may not support automatic mapping.").arg(device)); + return; + } + + bool result; + if (m_dialog->isEditingGlobalSettings()) + { + { + auto lock = Host::GetSettingsLock(); + result = USB::MapDevice(*Host::Internal::GetBaseSettingsLayer(), m_port_number, mapping); + } + if (result) + Host::CommitBaseSettingChanges(); + } + else + { + result = USB::MapDevice(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping); + if (result) + { + m_dialog->getProfileSettingsInterface()->Save(); + g_emu_thread->reloadInputBindings(); + } + } + + // force a refresh after mapping + if (result) + { + g_emu_thread->applySettings(); + onTypeChanged(); + } +} + +////////////////////////////////////////////////////////////////////////// + +USBBindingWidget::USBBindingWidget(USBDeviceWidget* parent) + : QWidget(parent) +{ +} + +USBBindingWidget::~USBBindingWidget() +{ +} + +QIcon USBBindingWidget::getIcon() const +{ + //return QIcon::fromTheme("gamepad-line"); + + return QIcon::fromTheme("artboard-2-line"); +} + +std::string USBBindingWidget::getBindingKey(const char* binding_name) const +{ + return USB::GetConfigBindKey(getDeviceType(), binding_name); +} + +void USBBindingWidget::createWidgets(gsl::span bindings) +{ + QGroupBox* axis_gbox = nullptr; + QGridLayout* axis_layout = nullptr; + QGroupBox* button_gbox = nullptr; + QGridLayout* button_layout = nullptr; + SettingsInterface* sif = getDialog()->getProfileSettingsInterface(); + + QScrollArea* scrollarea = new QScrollArea(this); + QWidget* scrollarea_widget = new QWidget(scrollarea); + scrollarea->setWidget(scrollarea_widget); + scrollarea->setWidgetResizable(true); + scrollarea->setFrameShape(QFrame::StyledPanel); + scrollarea->setFrameShadow(QFrame::Plain); + + // We do axes and buttons separately, so we can figure out how many columns to use. + constexpr int NUM_AXIS_COLUMNS = 2; + int column = 0; + int row = 0; + for (const InputBindingInfo& bi : bindings) + { + if (bi.bind_type == InputBindingInfo::Type::Axis || bi.bind_type == InputBindingInfo::Type::HalfAxis || + bi.bind_type == InputBindingInfo::Type::Pointer || bi.bind_type == InputBindingInfo::Type::Device) + { + if (!axis_gbox) + { + axis_gbox = new QGroupBox(tr("Axes"), scrollarea_widget); + axis_layout = new QGridLayout(axis_gbox); + } + + QGroupBox* gbox = new QGroupBox(qApp->translate("USB", bi.display_name), axis_gbox); + QVBoxLayout* temp = new QVBoxLayout(gbox); + InputBindingWidget* widget = new InputBindingWidget(gbox, sif, bi.bind_type, getConfigSection(), getBindingKey(bi.name)); + temp->addWidget(widget); + axis_layout->addWidget(gbox, row, column); + if ((++column) == NUM_AXIS_COLUMNS) + { + column = 0; + row++; + } + } + } + if (axis_gbox) + axis_layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), ++row, 0); + + const int num_button_columns = axis_layout ? 2 : 4; + row = 0; + column = 0; + for (const InputBindingInfo& bi : bindings) + { + if (bi.bind_type == InputBindingInfo::Type::Button) + { + if (!button_gbox) + { + button_gbox = new QGroupBox(tr("Buttons"), scrollarea_widget); + button_layout = new QGridLayout(button_gbox); + } + + QGroupBox* gbox = new QGroupBox(qApp->translate("USB", bi.display_name), button_gbox); + QVBoxLayout* temp = new QVBoxLayout(gbox); + InputBindingWidget* widget = new InputBindingWidget(gbox, sif, bi.bind_type, getConfigSection(), getBindingKey(bi.name)); + temp->addWidget(widget); + button_layout->addWidget(gbox, row, column); + if ((++column) == num_button_columns) + { + column = 0; + row++; + } + } + } + + if (button_gbox) + button_layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), ++row, 0); + + if (!axis_gbox && !button_gbox) + return; + + QHBoxLayout* layout = new QHBoxLayout(scrollarea_widget); + if (axis_gbox) + layout->addWidget(axis_gbox); + if (button_gbox) + layout->addWidget(button_gbox); + layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum)); + + QHBoxLayout* main_layout = new QHBoxLayout(this); + main_layout->addWidget(scrollarea); +} + + +void USBBindingWidget::bindWidgets(gsl::span bindings) +{ + SettingsInterface* sif = getDialog()->getProfileSettingsInterface(); + + for (const InputBindingInfo& bi : bindings) + { + if (bi.bind_type == InputBindingInfo::Type::Axis || bi.bind_type == InputBindingInfo::Type::HalfAxis || + bi.bind_type == InputBindingInfo::Type::Button || bi.bind_type == InputBindingInfo::Type::Pointer || + bi.bind_type == InputBindingInfo::Type::Device) + { + InputBindingWidget* widget = findChild(QString::fromUtf8(bi.name)); + if (!widget) + { + Console.Error("(USBBindingWidget) No widget found for '%s'.", bi.name); + continue; + } + + widget->initialize(sif, bi.bind_type, getConfigSection(), getBindingKey(bi.name)); + } + } +} + +USBBindingWidget* USBBindingWidget::createInstance( + const std::string& type, u32 subtype, gsl::span bindings, USBDeviceWidget* parent) +{ + USBBindingWidget* widget = new USBBindingWidget(parent); + bool has_template = false; + + if (type == "Pad") + { + if (subtype == 0) // Generic or Driving Force + { + Ui::USBBindingWidget_DrivingForce().setupUi(widget); + has_template = true; + } + else if (subtype == 3) // GT Force + { + Ui::USBBindingWidget_GTForce().setupUi(widget); + has_template = true; + } + } + + if (has_template) + widget->bindWidgets(bindings); + else + widget->createWidgets(bindings); + + return widget; +} diff --git a/pcsx2-qt/Settings/ControllerBindingWidgets.h b/pcsx2-qt/Settings/ControllerBindingWidgets.h index e12dd2992f..04d33614c0 100644 --- a/pcsx2-qt/Settings/ControllerBindingWidgets.h +++ b/pcsx2-qt/Settings/ControllerBindingWidgets.h @@ -19,10 +19,13 @@ #include +#include "gsl/span" + #include "ui_ControllerBindingWidget.h" #include "ui_ControllerBindingWidget_DualShock2.h" #include "ui_ControllerMacroWidget.h" #include "ui_ControllerMacroEditWidget.h" +#include "ui_USBDeviceWidget.h" class InputBindingWidget; class ControllerSettingsDialog; @@ -31,6 +34,8 @@ class ControllerMacroWidget; class ControllerMacroEditWidget; class ControllerBindingWidget_Base; +class USBBindingWidget; + class ControllerBindingWidget final : public QWidget { Q_OBJECT @@ -133,16 +138,20 @@ class ControllerCustomSettingsWidget : public QWidget Q_OBJECT public: - ControllerCustomSettingsWidget(ControllerBindingWidget* parent, QWidget* parent_widget); + ControllerCustomSettingsWidget(gsl::span settings, std::string config_section, std::string config_prefix, + const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget); ~ControllerCustomSettingsWidget(); - void createSettingWidgets(ControllerBindingWidget* parent, QWidget* widget_parent, QGridLayout* layout, const PAD::ControllerInfo* cinfo); - private Q_SLOTS: void restoreDefaults(); private: - ControllerBindingWidget* m_parent; + void createSettingWidgets(const char* translation_ctx, QWidget* widget_parent, QGridLayout* layout); + + gsl::span m_settings; + std::string m_config_section; + std::string m_config_prefix; + ControllerSettingsDialog* m_dialog; }; ////////////////////////////////////////////////////////////////////////// @@ -182,3 +191,71 @@ public: private: Ui::ControllerBindingWidget_DualShock2 m_ui; }; + +////////////////////////////////////////////////////////////////////////// + +class USBDeviceWidget final : public QWidget +{ + Q_OBJECT + +public: + USBDeviceWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port); + ~USBDeviceWidget(); + + QIcon getIcon() const; + + __fi ControllerSettingsDialog* getDialog() const { return m_dialog; } + __fi const std::string& getConfigSection() const { return m_config_section; } + __fi const std::string& getDeviceType() const { return m_device_type; } + __fi u32 getPortNumber() const { return m_port_number; } + +private Q_SLOTS: + void onTypeChanged(); + void onSubTypeChanged(int new_index); + void onAutomaticBindingClicked(); + void onClearBindingsClicked(); + void onBindingsClicked(); + void onSettingsClicked(); + +private: + void populateDeviceTypes(); + void populatePages(); + void updateHeaderToolButtons(); + void doDeviceAutomaticBinding(const QString& device); + + Ui::USBDeviceWidget m_ui; + + ControllerSettingsDialog* m_dialog; + + std::string m_config_section; + std::string m_device_type; + u32 m_device_subtype; + u32 m_port_number; + + USBBindingWidget* m_bindings_widget = nullptr; + ControllerCustomSettingsWidget* m_settings_widget = nullptr; +}; + +class USBBindingWidget : public QWidget +{ + Q_OBJECT + +public: + USBBindingWidget(USBDeviceWidget* parent); + ~USBBindingWidget() override; + + __fi ControllerSettingsDialog* getDialog() const { return static_cast(parent())->getDialog(); } + __fi const std::string& getConfigSection() const { return static_cast(parent())->getConfigSection(); } + __fi const std::string& getDeviceType() const { return static_cast(parent())->getDeviceType(); } + __fi u32 getPortNumber() const { return static_cast(parent())->getPortNumber(); } + + QIcon getIcon() const; + + static USBBindingWidget* createInstance(const std::string& type, u32 subtype, gsl::span bindings, USBDeviceWidget* parent); + +protected: + std::string getBindingKey(const char* binding_name) const; + + void createWidgets(gsl::span bindings); + void bindWidgets(gsl::span bindings); +}; diff --git a/pcsx2-qt/Settings/ControllerSettingsDialog.cpp b/pcsx2-qt/Settings/ControllerSettingsDialog.cpp index edb33401ec..a32fe3c203 100644 --- a/pcsx2-qt/Settings/ControllerSettingsDialog.cpp +++ b/pcsx2-qt/Settings/ControllerSettingsDialog.cpp @@ -114,7 +114,8 @@ void ControllerSettingsDialog::onNewProfileClicked() } const int res = QMessageBox::question(this, tr("Create Input Profile"), - tr("Do you want to copy all bindings from the currently-selected profile to the new profile? Selecting No will create a completely empty profile."), + tr("Do you want to copy all bindings from the currently-selected profile to the new profile? Selecting No will create a completely " + "empty profile."), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); if (res == QMessageBox::Cancel) return; @@ -140,7 +141,8 @@ void ControllerSettingsDialog::onNewProfileClicked() if (!temp_si.Save()) { - QMessageBox::critical(this, tr("Error"), tr("Failed to save the new profile to '%1'.").arg(QString::fromStdString(temp_si.GetFileName()))); + QMessageBox::critical( + this, tr("Error"), tr("Failed to save the new profile to '%1'.").arg(QString::fromStdString(temp_si.GetFileName()))); return; } @@ -252,7 +254,7 @@ void ControllerSettingsDialog::onVibrationMotorsEnumerated(const QList mtap_enabled = {{getBoolValue("Pad", "MultitapPort1", false), - getBoolValue("Pad", "MultitapPort2", false)}}; + const std::array mtap_enabled = {{getBoolValue("Pad", "MultitapPort1", false), getBoolValue("Pad", "MultitapPort2", false)}}; // we reorder things a little to make it look less silly for mtap static constexpr const std::array mtap_port_order = {{0, 2, 3, 4, 1, 5, 6, 7}}; @@ -401,14 +402,29 @@ void ControllerSettingsDialog::createWidgets() const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown")); QListWidgetItem* item = new QListWidgetItem(); - item->setText(mtap_enabled[port] ? - (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) : - tr("Controller Port %1\n%2").arg(port + 1).arg(display_name)); + item->setText(mtap_enabled[port] ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) : + tr("Controller Port %1\n%2").arg(port + 1).arg(display_name)); item->setIcon(m_port_bindings[global_slot]->getIcon()); item->setData(Qt::UserRole, QVariant(global_slot)); m_ui.settingsCategory->addItem(item); } + // USB ports + for (u32 port = 0; port < USB::NUM_PORTS; port++) + { + m_usb_bindings[port] = new USBDeviceWidget(m_ui.settingsContainer, this, port); + m_ui.settingsContainer->addWidget(m_usb_bindings[port]); + + const std::string dtype(getStringValue(fmt::format("USB{}", port + 1).c_str(), "Type", "None")); + const QString display_name(qApp->translate("USB", USB::GetDeviceName(dtype))); + + QListWidgetItem* item = new QListWidgetItem(); + item->setText(tr("USB Port %1\n%2").arg(port + 1).arg(display_name)); + item->setIcon(m_usb_bindings[port]->getIcon()); + item->setData(Qt::UserRole, QVariant(MAX_PORTS + port)); + m_ui.settingsCategory->addItem(item); + } + // only add hotkeys if we're editing global settings if (!m_profile_interface || m_profile_interface->GetBoolValue("Pad", "UseProfileHotkeyBindings", false)) { @@ -439,14 +455,32 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller const PAD::ControllerInfo* ci = PAD::GetControllerInfo(widget->getControllerType()); const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown")); - item->setText(mtap_enabled ? - (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) : - tr("Controller Port %1\n%2").arg(port + 1).arg(display_name)); + item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) : + tr("Controller Port %1\n%2").arg(port + 1).arg(display_name)); item->setIcon(widget->getIcon()); break; } } } + +void ControllerSettingsDialog::updateListDescription(u32 port, USBDeviceWidget* widget) +{ + for (int i = 0; i < m_ui.settingsCategory->count(); i++) + { + QListWidgetItem* item = m_ui.settingsCategory->item(i); + const QVariant data(item->data(Qt::UserRole)); + if (data.type() == QVariant::UInt && data.toUInt() == (MAX_PORTS + port)) + { + const std::string dtype(getStringValue(fmt::format("USB{}", port + 1).c_str(), "Type", "None")); + const QString display_name(qApp->translate("USB", USB::GetDeviceName(dtype))); + + item->setText(tr("USB Port %1\n%2").arg(port + 1).arg(display_name)); + item->setIcon(widget->getIcon()); + break; + } + } +} + void ControllerSettingsDialog::refreshProfileList() { const std::vector names(PAD::GetInputProfileNames()); diff --git a/pcsx2-qt/Settings/ControllerSettingsDialog.h b/pcsx2-qt/Settings/ControllerSettingsDialog.h index 1569ebb099..79ac51bc55 100644 --- a/pcsx2-qt/Settings/ControllerSettingsDialog.h +++ b/pcsx2-qt/Settings/ControllerSettingsDialog.h @@ -15,7 +15,8 @@ #pragma once #include "ui_ControllerSettingsDialog.h" -#include "Frontend/InputManager.h" +#include "pcsx2/Frontend/InputManager.h" +#include "pcsx2/USB/USB.h" #include #include #include @@ -27,6 +28,7 @@ class ControllerGlobalSettingsWidget; class ControllerBindingWidget; class HotkeySettingsWidget; +class USBDeviceWidget; class SettingsInterface; @@ -61,6 +63,7 @@ public: __fi SettingsInterface* getProfileSettingsInterface() { return m_profile_interface.get(); } void updateListDescription(u32 global_slot, ControllerBindingWidget* widget); + void updateListDescription(u32 port, USBDeviceWidget* widget); // Helper functions for updating setting values globally or in the profile. bool getBoolValue(const char* section, const char* key, bool default_value) const; @@ -93,8 +96,6 @@ private Q_SLOTS: void createWidgets(); private: - static QIcon getIconForType(const std::string& type); - void refreshProfileList(); void switchProfile(const QString& name); @@ -102,6 +103,7 @@ private: ControllerGlobalSettingsWidget* m_global_settings = nullptr; std::array m_port_bindings{}; + std::array m_usb_bindings{}; HotkeySettingsWidget* m_hotkey_settings = nullptr; QList> m_device_list; diff --git a/pcsx2-qt/Settings/ControllerSettingsDialog.ui b/pcsx2-qt/Settings/ControllerSettingsDialog.ui index 4b4fdedede..6d459157e9 100644 --- a/pcsx2-qt/Settings/ControllerSettingsDialog.ui +++ b/pcsx2-qt/Settings/ControllerSettingsDialog.ui @@ -9,7 +9,7 @@ 0 0 - 1300 + 1305 680 @@ -33,13 +33,13 @@ - 150 + 170 0 - 150 + 170 16777215 @@ -92,7 +92,8 @@ Load Profile - + + .. @@ -113,7 +114,8 @@ Restore Defaults - + + .. diff --git a/pcsx2-qt/Settings/HotkeySettingsWidget.cpp b/pcsx2-qt/Settings/HotkeySettingsWidget.cpp index 4c25ba7b7f..a344fa8b32 100644 --- a/pcsx2-qt/Settings/HotkeySettingsWidget.cpp +++ b/pcsx2-qt/Settings/HotkeySettingsWidget.cpp @@ -88,7 +88,8 @@ void HotkeySettingsWidget::createButtons() QLabel* label = new QLabel(qApp->translate("Hotkeys", hotkey->display_name), m_container); layout->addWidget(label, target_row, 0); - InputBindingWidget* bind = new InputBindingWidget(m_container, m_dialog->getProfileSettingsInterface(), "Hotkeys", hotkey->name); + InputBindingWidget* bind = new InputBindingWidget( + m_container, m_dialog->getProfileSettingsInterface(), InputBindingInfo::Type::Button, "Hotkeys", hotkey->name); bind->setMinimumWidth(300); layout->addWidget(bind, target_row, 1); } diff --git a/pcsx2-qt/Settings/InputBindingDialog.cpp b/pcsx2-qt/Settings/InputBindingDialog.cpp index 3a6ebeddda..af336b3416 100644 --- a/pcsx2-qt/Settings/InputBindingDialog.cpp +++ b/pcsx2-qt/Settings/InputBindingDialog.cpp @@ -27,17 +27,17 @@ // _BitScanForward() #include "pcsx2/GS/GSIntrin.h" -InputBindingDialog::InputBindingDialog(SettingsInterface* sif, std::string section_name, std::string key_name, - std::vector bindings, QWidget* parent) +InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, + std::string key_name, std::vector bindings, QWidget* parent) : QDialog(parent) , m_sif(sif) + , m_bind_type(bind_type) , m_section_name(std::move(section_name)) , m_key_name(std::move(key_name)) , m_bindings(std::move(bindings)) { m_ui.setupUi(this); - m_ui.title->setText( - tr("Bindings for %1 %2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name))); + m_ui.title->setText(tr("Bindings for %1 %2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name))); m_ui.buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close")); connect(m_ui.addBinding, &QPushButton::clicked, this, &InputBindingDialog::onAddBindingButtonClicked); @@ -159,8 +159,7 @@ void InputBindingDialog::startListeningForInput(u32 timeout_in_seconds) m_input_listen_timer->setSingleShot(false); m_input_listen_timer->start(1000); - m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this, - &InputBindingDialog::onInputListenTimerTimeout); + m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this, &InputBindingDialog::onInputListenTimerTimeout); m_input_listen_remaining_seconds = timeout_in_seconds; m_ui.status->setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds)); m_ui.addBinding->setEnabled(false); @@ -198,8 +197,7 @@ void InputBindingDialog::addNewBinding() if (m_new_bindings.empty()) return; - const std::string new_binding( - InputManager::ConvertInputBindingKeysToString(m_new_bindings.data(), m_new_bindings.size())); + const std::string new_binding(InputManager::ConvertInputBindingKeysToString(m_bind_type, m_new_bindings.data(), m_new_bindings.size())); if (!new_binding.empty()) { if (std::find(m_bindings.begin(), m_bindings.end(), new_binding) != m_bindings.end()) @@ -299,8 +297,7 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val void InputBindingDialog::hookInputManager() { InputManager::SetHook([this](InputBindingKey key, float value) { - QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key), - Q_ARG(float, value)); + QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key), Q_ARG(float, value)); return InputInterceptHook::CallbackResult::StopProcessingEvent; }); } diff --git a/pcsx2-qt/Settings/InputBindingDialog.h b/pcsx2-qt/Settings/InputBindingDialog.h index 510e0f12d2..c50dd08033 100644 --- a/pcsx2-qt/Settings/InputBindingDialog.h +++ b/pcsx2-qt/Settings/InputBindingDialog.h @@ -15,7 +15,8 @@ #pragma once #include "ui_InputBindingDialog.h" -#include "Frontend/InputManager.h" +#include "pcsx2/Config.h" +#include "pcsx2/Frontend/InputManager.h" #include #include #include @@ -28,7 +29,8 @@ class InputBindingDialog : public QDialog Q_OBJECT public: - InputBindingDialog(SettingsInterface* sif, std::string section_name, std::string key_name, std::vector bindings, QWidget* parent); + InputBindingDialog(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name, + std::vector bindings, QWidget* parent); ~InputBindingDialog(); protected Q_SLOTS: @@ -61,6 +63,7 @@ protected: Ui::InputBindingDialog m_ui; SettingsInterface* m_sif; + InputBindingInfo::Type m_bind_type; std::string m_section_name; std::string m_key_name; std::vector m_bindings; diff --git a/pcsx2-qt/Settings/InputBindingWidget.cpp b/pcsx2-qt/Settings/InputBindingWidget.cpp index eecc820552..4832783710 100644 --- a/pcsx2-qt/Settings/InputBindingWidget.cpp +++ b/pcsx2-qt/Settings/InputBindingWidget.cpp @@ -40,7 +40,8 @@ InputBindingWidget::InputBindingWidget(QWidget* parent) connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked); } -InputBindingWidget::InputBindingWidget(QWidget* parent, SettingsInterface* sif, std::string section_name, std::string key_name) +InputBindingWidget::InputBindingWidget( + QWidget* parent, SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name) : QPushButton(parent) { setMinimumWidth(225); @@ -48,7 +49,7 @@ InputBindingWidget::InputBindingWidget(QWidget* parent, SettingsInterface* sif, connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked); - initialize(sif, std::move(section_name), std::move(key_name)); + initialize(sif, bind_type, std::move(section_name), std::move(key_name)); } InputBindingWidget::~InputBindingWidget() @@ -61,9 +62,11 @@ bool InputBindingWidget::isMouseMappingEnabled() return Host::GetBaseBoolSettingValue("UI", "EnableMouseMapping", false); } -void InputBindingWidget::initialize(SettingsInterface* sif, std::string section_name, std::string key_name) +void InputBindingWidget::initialize( + SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name) { m_sif = sif; + m_bind_type = bind_type; m_section_name = std::move(section_name); m_key_name = std::move(key_name); reloadBinding(); @@ -223,8 +226,7 @@ void InputBindingWidget::setNewBinding() if (m_new_bindings.empty()) return; - const std::string new_binding( - InputManager::ConvertInputBindingKeysToString(m_new_bindings.data(), m_new_bindings.size())); + std::string new_binding(InputManager::ConvertInputBindingKeysToString(m_bind_type, m_new_bindings.data(), m_new_bindings.size())); if (!new_binding.empty()) { if (m_sif) @@ -265,9 +267,8 @@ void InputBindingWidget::clearBinding() void InputBindingWidget::reloadBinding() { - m_bindings = m_sif ? - m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) : - Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str()); + m_bindings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) : + Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str()); updateText(); } @@ -306,8 +307,7 @@ void InputBindingWidget::startListeningForInput(u32 timeout_in_seconds) m_input_listen_timer->setSingleShot(false); m_input_listen_timer->start(1000); - m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this, - &InputBindingWidget::onInputListenTimerTimeout); + m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this, &InputBindingWidget::onInputListenTimerTimeout); m_input_listen_remaining_seconds = timeout_in_seconds; setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds)); @@ -365,8 +365,7 @@ void InputBindingWidget::inputManagerHookCallback(InputBindingKey key, float val void InputBindingWidget::hookInputManager() { InputManager::SetHook([this](InputBindingKey key, float value) { - QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key), - Q_ARG(float, value)); + QMetaObject::invokeMethod(this, "inputManagerHookCallback", Qt::QueuedConnection, Q_ARG(InputBindingKey, key), Q_ARG(float, value)); return InputInterceptHook::CallbackResult::StopProcessingEvent; }); } @@ -378,7 +377,7 @@ void InputBindingWidget::unhookInputManager() void InputBindingWidget::openDialog() { - InputBindingDialog binding_dialog(m_sif, m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this)); + InputBindingDialog binding_dialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this)); binding_dialog.exec(); reloadBinding(); } @@ -388,7 +387,8 @@ InputVibrationBindingWidget::InputVibrationBindingWidget(QWidget* parent) connect(this, &QPushButton::clicked, this, &InputVibrationBindingWidget::onClicked); } -InputVibrationBindingWidget::InputVibrationBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, std::string section_name, std::string key_name) +InputVibrationBindingWidget::InputVibrationBindingWidget( + QWidget* parent, ControllerSettingsDialog* dialog, std::string section_name, std::string key_name) { setMinimumWidth(225); setMaximumWidth(225); diff --git a/pcsx2-qt/Settings/InputBindingWidget.h b/pcsx2-qt/Settings/InputBindingWidget.h index c8e744b730..826b75f120 100644 --- a/pcsx2-qt/Settings/InputBindingWidget.h +++ b/pcsx2-qt/Settings/InputBindingWidget.h @@ -16,6 +16,7 @@ #pragma once #include "common/Pcsx2Defs.h" #include "pcsx2/Frontend/InputManager.h" +#include "pcsx2/Config.h" #include #include @@ -30,12 +31,13 @@ class InputBindingWidget : public QPushButton public: InputBindingWidget(QWidget* parent); - InputBindingWidget(QWidget* parent, SettingsInterface* sif, std::string section_name, std::string key_name); + InputBindingWidget( + QWidget* parent, SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name); ~InputBindingWidget(); static bool isMouseMappingEnabled(); - void initialize(SettingsInterface* sif, std::string section_name, std::string key_name); + void initialize(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name); public Q_SLOTS: void clearBinding(); @@ -69,6 +71,7 @@ protected: void unhookInputManager(); SettingsInterface* m_sif = nullptr; + InputBindingInfo::Type m_bind_type = InputBindingInfo::Type::Unknown; std::string m_section_name; std::string m_key_name; std::vector m_bindings; @@ -103,6 +106,6 @@ private: std::string m_section_name; std::string m_key_name; std::string m_binding; - + ControllerSettingsDialog* m_dialog; }; diff --git a/pcsx2-qt/Settings/USBBindingWidget_DrivingForce.ui b/pcsx2-qt/Settings/USBBindingWidget_DrivingForce.ui new file mode 100644 index 0000000000..04cb1024fc --- /dev/null +++ b/pcsx2-qt/Settings/USBBindingWidget_DrivingForce.ui @@ -0,0 +1,992 @@ + + + USBBindingWidget_DrivingForce + + + + 0 + 0 + 1102 + 476 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Hints + + + + + + To bind steering for most modern 900 degree wheels, turn the wheel one rotation in the desired direction, then back again to center. + + + true + + + + + + + + + + Force Feedback + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + + + + + D-Pad + + + + + + Down + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + Left + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + Up + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + Right + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + + + + L1 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + L2 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Brake + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + + + + Steering Left + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + Steering Right + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 400 + 266 + + + + + 400 + 266 + + + + + + + :/images/DrivingForce.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Select + + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + + 200 + 0 + + + + Start + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Face Buttons + + + + + + Circle + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + Cross + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + Triangle + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + Square + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 125 + 0 + + + + + 125 + 16777215 + + + + PushButton + + + + + + + + + + + + + R1 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + R2 + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Accelerator + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + InputBindingWidget + QPushButton +
Settings/InputBindingWidget.h
+
+
+ + + + +
diff --git a/pcsx2-qt/Settings/USBBindingWidget_GTForce.ui b/pcsx2-qt/Settings/USBBindingWidget_GTForce.ui new file mode 100644 index 0000000000..e5912ed9a0 --- /dev/null +++ b/pcsx2-qt/Settings/USBBindingWidget_GTForce.ui @@ -0,0 +1,683 @@ + + + USBBindingWidget_GTForce + + + + 0 + 0 + 1389 + 521 + + + + + 0 + 0 + + + + + 1100 + 500 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Hints + + + + + + To bind steering for most modern 900 degree wheels, turn the wheel one rotation in the desired direction, then back again to center. + + + true + + + + + + + + + + Force Feedback + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + X + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + A + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Brake + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Steering Left + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + Steering Right + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 400 + 266 + + + + + + + :/images/GTForce.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Left Paddle + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + + 200 + 0 + + + + Right Paddle + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + PushButton + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Y + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + B + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Accelerator + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + PushButton + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + InputBindingWidget + QPushButton +
Settings/InputBindingWidget.h
+
+
+ + + + +
diff --git a/pcsx2-qt/Settings/USBDeviceWidget.ui b/pcsx2-qt/Settings/USBDeviceWidget.ui new file mode 100644 index 0000000000..0bb31796a7 --- /dev/null +++ b/pcsx2-qt/Settings/USBDeviceWidget.ui @@ -0,0 +1,142 @@ + + + USBDeviceWidget + + + + 0 + 0 + 833 + 617 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Device Type + + + + + + + + + + + + + + Bindings + + + + .. + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Settings + + + + .. + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + + Qt::Horizontal + + + + 460 + 20 + + + + + + + + + + Automatic Mapping + + + + .. + + + Qt::ToolButtonTextBesideIcon + + + + + + + Clear Mapping + + + + .. + + + Qt::ToolButtonTextBesideIcon + + + + + + + + + + + + + + + + + + diff --git a/pcsx2-qt/pcsx2-qt.vcxproj b/pcsx2-qt/pcsx2-qt.vcxproj index 34e7ef0e55..54ef848b3c 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj +++ b/pcsx2-qt/pcsx2-qt.vcxproj @@ -361,6 +361,11 @@ + + + + Document + Document @@ -372,4 +377,4 @@ - + \ No newline at end of file diff --git a/pcsx2-qt/pcsx2-qt.vcxproj.filters b/pcsx2-qt/pcsx2-qt.vcxproj.filters index 88777df26c..7b126738ce 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj.filters +++ b/pcsx2-qt/pcsx2-qt.vcxproj.filters @@ -269,9 +269,6 @@ Settings - - Tools\Input Recording - @@ -368,6 +365,7 @@ Settings + @@ -462,10 +460,19 @@ Tools\Input Recording + + Settings + Settings + + Settings + + + Settings + - + \ No newline at end of file diff --git a/pcsx2-qt/resources/icons/black/svg/usb-fill.svg b/pcsx2-qt/resources/icons/black/svg/usb-fill.svg new file mode 100644 index 0000000000..a88de34035 --- /dev/null +++ b/pcsx2-qt/resources/icons/black/svg/usb-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pcsx2-qt/resources/icons/white/svg/usb-fill.svg b/pcsx2-qt/resources/icons/white/svg/usb-fill.svg new file mode 100644 index 0000000000..027465a994 --- /dev/null +++ b/pcsx2-qt/resources/icons/white/svg/usb-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pcsx2-qt/resources/images/DrivingForce.png b/pcsx2-qt/resources/images/DrivingForce.png new file mode 100644 index 0000000000..5c03762368 Binary files /dev/null and b/pcsx2-qt/resources/images/DrivingForce.png differ diff --git a/pcsx2-qt/resources/images/GTForce.png b/pcsx2-qt/resources/images/GTForce.png new file mode 100644 index 0000000000..6b94352ce0 Binary files /dev/null and b/pcsx2-qt/resources/images/GTForce.png differ diff --git a/pcsx2-qt/resources/resources.qrc b/pcsx2-qt/resources/resources.qrc index 3b2aeab90c..d68738265e 100644 --- a/pcsx2-qt/resources/resources.qrc +++ b/pcsx2-qt/resources/resources.qrc @@ -50,6 +50,7 @@ icons/black/svg/shut-down-line.svg icons/black/svg/trophy-line.svg icons/black/svg/tv-2-line.svg + icons/black/svg/usb-fill.svg icons/black/svg/volume-up-line.svg icons/black/svg/window-2-line.svg icons/discord.png @@ -107,8 +108,11 @@ icons/white/svg/shut-down-line.svg icons/white/svg/trophy-line.svg icons/white/svg/tv-2-line.svg + icons/white/svg/usb-fill.svg icons/white/svg/volume-up-line.svg icons/white/svg/window-2-line.svg + images/DrivingForce.png + images/GTForce.png images/dualshock-2.png diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 052b9a71b7..737acad5d4 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -439,91 +439,77 @@ endif() # USBNull set(pcsx2USBNullSources USB/USBNull.cpp) -set(pcsx2USBNullHeaders USB/USB.h) +set(pcsx2USBNullHeaders USB/USBNull.h) # USB sources set(pcsx2USBSources USB/USB.cpp USB/deviceproxy.cpp - USB/configuration.cpp - USB/device_init.cpp - USB/qemu-usb/glib.cpp - USB/qemu-usb/vl.cpp - USB/qemu-usb/iov.cpp - USB/qemu-usb/desc.cpp - USB/qemu-usb/core.cpp USB/qemu-usb/bus.cpp - USB/qemu-usb/usb-ohci.cpp + USB/qemu-usb/core.cpp + USB/qemu-usb/desc.cpp USB/qemu-usb/hid.cpp USB/qemu-usb/input-keymap-qcode-to-qnum.cpp - USB/usb-msd/usb-msd.cpp - USB/usb-pad/usb-pad.cpp - USB/usb-pad/usb-pad-ff.cpp - USB/usb-pad/lg/lg_ff.cpp - USB/usb-pad/usb-seamic.cpp - USB/usb-mic/usb-mic-singstar.cpp - USB/usb-mic/usb-mic-logitech.cpp - USB/usb-mic/usb-headset.cpp + USB/qemu-usb/iov.cpp + USB/qemu-usb/usb-ohci.cpp + USB/shared/ringbuffer.cpp USB/usb-eyetoy/jo_mpeg.cpp USB/usb-eyetoy/usb-eyetoy-webcam.cpp USB/usb-hid/usb-hid.cpp - USB/shared/shared_usb.cpp - USB/shared/inifile_usb.cpp - USB/shared/ringbuffer.cpp + USB/usb-lightgun/guncon2.cpp + USB/usb-mic/usb-headset.cpp + USB/usb-mic/usb-mic-logitech.cpp + USB/usb-mic/usb-mic-singstar.cpp + USB/usb-msd/usb-msd.cpp + USB/usb-pad/lg/lg_ff.cpp + USB/usb-pad/usb-pad-ff.cpp + USB/usb-pad/usb-pad.cpp + USB/usb-pad/usb-seamic.cpp USB/usb-printer/usb-printer.cpp - ) +) # USB headers set(pcsx2USBHeaders USB/USB.h - USB/proxybase.h USB/deviceproxy.h - USB/configuration.h - USB/platcompat.h - USB/helpers.h - USB/readerwriterqueue/readerwriterqueue.h - USB/readerwriterqueue/atomicops.h - USB/qemu-usb/glib.h - USB/qemu-usb/vl.h - USB/qemu-usb/qusb.h USB/qemu-usb/USBinternal.h USB/qemu-usb/desc.h - USB/qemu-usb/iov.h - USB/qemu-usb/queue.h USB/qemu-usb/hid.h USB/qemu-usb/input-keymap.h - USB/usb-msd/usb-msd.h - USB/usb-pad/usb-pad.h - USB/usb-pad/padproxy.h - USB/usb-pad/lg/lg_ff.h - USB/usb-mic/audio.h - USB/usb-mic/audiodev.h - USB/usb-mic/audiodeviceproxy.h - USB/usb-mic/usb-mic-singstar.h - USB/usb-mic/usb-headset.h - USB/usb-mic/audiodev-noop.h - ../3rdparty/jpgd/jpgd.h - ../3rdparty/jpgd/jpge.h - USB/usb-eyetoy/jo_mpeg.h - USB/usb-eyetoy/videodeviceproxy.h - USB/usb-eyetoy/videodev.h - USB/usb-eyetoy/usb-eyetoy-webcam.h - USB/usb-eyetoy/ov519.h - USB/usb-hid/hidproxy.h - USB/usb-hid/usb-hid.h - USB/usb-hid/noop.h - USB/shared/shared_usb.h - USB/shared/inifile_usb.h + USB/qemu-usb/iov.h + USB/qemu-usb/queue.h + USB/qemu-usb/qusb.h + USB/readerwriterqueue/atomicops.h + USB/readerwriterqueue/readerwriterqueue.h USB/shared/ringbuffer.h + USB/usb-eyetoy/jo_mpeg.h + USB/usb-eyetoy/ov519.h + USB/usb-eyetoy/usb-eyetoy-webcam.h + USB/usb-eyetoy/videodev.h + USB/usb-hid/usb-hid.h + USB/usb-lightgun/guncon2.h + USB/usb-mic/audio.h + USB/usb-mic/audiodev-noop.h + USB/usb-mic/audiodev.h + USB/usb-mic/usb-headset.h + USB/usb-mic/usb-mic-singstar.h + USB/usb-msd/usb-msd.h + USB/usb-pad/lg/lg_ff.h + USB/usb-pad/usb-pad.h USB/usb-printer/usb-printer.h - ) +) -if(TARGET PulseAudio::PulseAudio) - list(APPEND pcsx2USBSources USB/usb-mic/audiodev-pulse.cpp) - list(APPEND pcsx2USBHeaders USB/usb-mic/audiodev-pulse.h) - target_link_libraries(PCSX2_FLAGS INTERFACE PulseAudio::PulseAudio) +if(CUBEB_API) + list(APPEND pcsx2USBSources USB/usb-mic/audiodev-cubeb.cpp) + list(APPEND pcsx2USBHeaders USB/usb-mic/audiodev-cubeb.h) endif() +if(TARGET SDL2::SDL2 OR TARGET SDL2::SDL2-static) + list(APPEND pcsx2USBSources USB/usb-pad/usb-pad-sdl-ff.cpp) + list(APPEND pcsx2USBHeaders USB/usb-pad/usb-pad-sdl-ff.h) +endif() + + if(PCSX2_CORE) # Host PAD set(pcsx2PADSources @@ -887,36 +873,10 @@ if(WIN32) ) list(APPEND pcsx2USBSources - USB/qemu-usb/input-keymap-win32-to-qcode.cpp - USB/shared/hidapi.cpp - USB/shared/rawinput_usb.cpp - USB/usb-eyetoy/api_init_win32_eyetoy.cpp USB/usb-eyetoy/cam-windows.cpp - USB/usb-hid/api_init_win32_hid.cpp - USB/usb-hid/raw/rawinput.cpp - USB/usb-mic/api_init_win32_mic.cpp - USB/usb-mic/audiodev-wasapi.cpp - USB/usb-msd/usb-msd-win32.cpp - USB/usb-pad/api_init_win32_pad.cpp - USB/usb-pad/dx/dinput-config.cpp - USB/usb-pad/dx/dinput.cpp - USB/usb-pad/dx/usb-pad-dx.cpp - USB/usb-pad/raw/raw-config.cpp - USB/usb-pad/raw/usb-pad-raw.cpp - USB/Win32/Config_usb.cpp ) list(APPEND pcsx2USBHeaders - USB/qemu-usb/input-keymap-win32-to-qcode.h - USB/shared/rawinput_usb.h USB/usb-eyetoy/cam-windows.h - USB/usb-mic/audiodev-wasapi.h - USB/usb-pad/dx/dx.h - USB/usb-pad/dx/usb-pad-dx.h - USB/usb-pad/dx/versionproxy.h - USB/usb-pad/raw/raw-config-res.h - USB/usb-pad/raw/usb-pad-raw.h - USB/Win32/Config_usb.h - USB/Win32/resource_usb.h ) list(APPEND pcsx2GSSources @@ -936,39 +896,16 @@ if(WIN32) GS/Renderers/DX12/GSDevice12.h GS/Renderers/DX12/GSTexture12.h ) -else() +elseif(Linux) list(APPEND pcsx2USBSources - USB/icon_buzz_24.cpp - USB/linux/config-gtk.cpp - USB/linux/config.cpp - USB/linux/util.cpp - USB/qemu-usb/input-keymap-linux-to-qcode.cpp - USB/usb-eyetoy/api_init_linux.cpp USB/usb-eyetoy/cam-linux.cpp - USB/usb-hid/api_init_linux.cpp - USB/usb-hid/evdev/evdev-gtk.cpp - USB/usb-mic/api_init_linux.cpp - USB/usb-msd/usb-msd-gtk.cpp - USB/usb-pad/api_init_linux.cpp - USB/usb-pad/evdev/evdev-ff.cpp - USB/usb-pad/evdev/evdev-gtk.cpp - USB/usb-pad/evdev/evdev.cpp - USB/usb-pad/evdev/shared-gtk.cpp ) list(APPEND pcsx2USBHeaders - USB/gtk.h - USB/icon_buzz_24.h - USB/linux/actualfile.h - USB/linux/config.h - USB/linux/ini.h - USB/linux/util.h - USB/qemu-usb/input-keymap-linux-to-qcode.h USB/usb-eyetoy/cam-linux.h - USB/usb-hid/evdev/evdev.cpp - USB/usb-hid/evdev/evdev.h - USB/usb-pad/evdev/evdev-ff.h - USB/usb-pad/evdev/evdev.h - USB/usb-pad/evdev/shared.h + ) +else() + list(APPEND pcsx2USBSources + USB/usb-eyetoy/cam-noop.cpp ) endif() @@ -1654,6 +1591,13 @@ if(Windows) ${pcsx2WindowsHeaders}) endif() +if(PCSX2_CORE) + target_sources(PCSX2 PRIVATE ${pcsx2USBSources} ${pcsx2USBHeaders}) + target_link_libraries(PCSX2_FLAGS INTERFACE jpgd) +else() + target_sources(PCSX2 PRIVATE ${pcsx2USBNullSources} ${pcsx2USBNullHeaders}) +endif() + # MacOSX/BSD if(UNIX AND NOT Linux) if(APPLE) @@ -1664,23 +1608,7 @@ if(UNIX AND NOT Linux) ${pcsx2FreeBSDSources}) endif() target_sources(PCSX2 PRIVATE - ${pcsx2LinuxHeaders} - ${pcsx2USBNullSources} - ${pcsx2USBNullHeaders}) -else() - if(NOT PCSX2_CORE) - target_sources(PCSX2 PRIVATE - ${pcsx2USBSources} - ${pcsx2USBHeaders}) - target_link_libraries(PCSX2_FLAGS INTERFACE - jpgd - PkgConfig::SAMPLERATE - ) - else() - target_sources(PCSX2 PRIVATE - ${pcsx2USBNullSources} - ${pcsx2USBNullHeaders}) - endif() + ${pcsx2LinuxHeaders}) endif() target_link_libraries(PCSX2_FLAGS INTERFACE @@ -1872,8 +1800,6 @@ function(setup_main_executable target) ${PCSX2_SOURCE_DIR}/GS/GS.rc ${PCSX2_SOURCE_DIR}/PAD/Windows/PAD.rc ${PCSX2_SOURCE_DIR}/SPU2/Windows/SPU2.rc - ${PCSX2_SOURCE_DIR}/USB/usb-pad/dx/versionproxy.rc - ${PCSX2_SOURCE_DIR}/USB/usb-pad/raw/raw-config.rc ) endif() target_sources(${target} PRIVATE diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 82c0ef1bea..1cf171145b 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -79,7 +79,10 @@ struct InputBindingInfo Axis, HalfAxis, Motor, - Macro + Pointer, // Receive relative mouse movement events, bind_index is offset by the axis. + Keyboard, // Receive host key events, bind_index is offset by the key code. + Device, // Used for special-purpose device selection, e.g. force feedback. + Macro, }; const char* name; @@ -1109,6 +1112,35 @@ struct Pcsx2Config } }; +#ifdef PCSX2_CORE + // ------------------------------------------------------------------------ + struct USBOptions + { + enum : u32 + { + NUM_PORTS = 2 + }; + + struct Port + { + s32 DeviceType; + u32 DeviceSubtype; + + bool operator==(const USBOptions::Port& right) const; + bool operator!=(const USBOptions::Port& right) const; + }; + + std::array Ports; + + USBOptions(); + void LoadSave(SettingsWrapper& wrap); + + bool operator==(const USBOptions& right) const; + bool operator!=(const USBOptions& right) const; + }; +#endif + + // ------------------------------------------------------------------------ // Options struct for each memory card. // @@ -1203,6 +1235,9 @@ struct Pcsx2Config FramerateOptions Framerate; SPU2Options SPU2; DEV9Options DEV9; +#ifdef PCSX2_CORE + USBOptions USB; +#endif TraceLogFilters Trace; diff --git a/pcsx2/Frontend/DInputSource.cpp b/pcsx2/Frontend/DInputSource.cpp index 01156fb32a..e71da9fe6d 100644 --- a/pcsx2/Frontend/DInputSource.cpp +++ b/pcsx2/Frontend/DInputSource.cpp @@ -155,7 +155,7 @@ bool DInputSource::ReloadDevices() { const u32 index = static_cast(m_controllers.size()); m_controllers.push_back(std::move(cd)); - Host::OnInputDeviceConnected(GetDeviceIdentifier(index), name); + InputManager::OnInputDeviceConnected(GetDeviceIdentifier(index), name); changed = true; } } @@ -167,7 +167,7 @@ void DInputSource::Shutdown() { while (!m_controllers.empty()) { - Host::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(m_controllers.size() - 1))); + InputManager::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(m_controllers.size() - 1))); m_controllers.pop_back(); } } @@ -268,7 +268,7 @@ void DInputSource::PollEvents() if (hr != DI_OK) { - Host::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(i))); + InputManager::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(i))); m_controllers.erase(m_controllers.begin() + i); continue; } diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index 957f917760..f0e4d336e3 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -1301,7 +1301,7 @@ void FullscreenUI::BeginInputBinding(SettingsInterface* bsi, InputBindingInfo::T // if this key is in our new binding list, it's a "release", and we're done SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); const std::string new_binding(InputManager::ConvertInputBindingKeysToString( - s_input_binding_new_bindings.data(), s_input_binding_new_bindings.size())); + s_input_binding_type, s_input_binding_new_bindings.data(), s_input_binding_new_bindings.size())); bsi->SetStringValue(s_input_binding_section.c_str(), s_input_binding_key.c_str(), new_binding.c_str()); SetSettingsChanged(bsi); ClearInputBindingVariables(); diff --git a/pcsx2/Frontend/ImGuiOverlays.cpp b/pcsx2/Frontend/ImGuiOverlays.cpp index 3fa6359c48..c86ec633c5 100644 --- a/pcsx2/Frontend/ImGuiOverlays.cpp +++ b/pcsx2/Frontend/ImGuiOverlays.cpp @@ -46,6 +46,7 @@ #ifdef PCSX2_CORE #include "PAD/Host/PAD.h" #include "PAD/Host/KeyStatus.h" +#include "USB/USB.h" #include "Frontend/FullscreenUI.h" #include "Frontend/ImGuiManager.h" #include "Frontend/ImGuiFullscreen.h" @@ -482,6 +483,12 @@ void ImGuiManager::DrawInputsOverlay() num_ports++; } + for (u32 port = 0; port < USB::NUM_PORTS; port++) + { + if (EmuConfig.USB.Ports[port].DeviceType >= 0 && !USB::GetDeviceBindings(port).empty()) + num_ports++; + } + float current_x = margin; float current_y = display_size.y - margin - ((static_cast(num_ports) * (font->FontSize + spacing)) - spacing); @@ -544,6 +551,59 @@ void ImGuiManager::DrawInputsOverlay() current_y += font->FontSize + spacing; } + + for (u32 port = 0; port < USB::NUM_PORTS; port++) + { + if (EmuConfig.USB.Ports[port].DeviceType < 0) + continue; + + const gsl::span bindings(USB::GetDeviceBindings(port)); + if (bindings.empty()) + continue; + + text.clear(); + fmt::format_to(std::back_inserter(text), "USB{} |", port + 1u); + + for (const InputBindingInfo& bi : bindings) + { + switch (bi.bind_type) + { + case InputBindingInfo::Type::Axis: + case InputBindingInfo::Type::HalfAxis: + { + // axes are always shown + const float value = static_cast(USB::GetDeviceBindValue(port, bi.bind_index)); + if (value >= (254.0f / 255.0f)) + fmt::format_to(std::back_inserter(text), " {}", bi.name); + else if (value > (1.0f / 255.0f)) + fmt::format_to(std::back_inserter(text), " {}: {:.2f}", bi.name, value); + } + break; + + case InputBindingInfo::Type::Button: + { + // buttons only shown when active + const float value = static_cast(USB::GetDeviceBindValue(port, bi.bind_index)); + if (value >= 0.5f) + fmt::format_to(std::back_inserter(text), " {}", bi.name); + } + break; + + case InputBindingInfo::Type::Motor: + case InputBindingInfo::Type::Macro: + case InputBindingInfo::Type::Unknown: + default: + break; + } + } + + dl->AddText(font, font->FontSize, ImVec2(current_x + shadow_offset, current_y + shadow_offset), shadow_color, text.c_str(), + text.c_str() + text.length(), 0.0f, &clip_rect); + dl->AddText( + font, font->FontSize, ImVec2(current_x, current_y), text_color, text.c_str(), text.c_str() + text.length(), 0.0f, &clip_rect); + + current_y += font->FontSize + spacing; + } } #endif diff --git a/pcsx2/Frontend/InputManager.cpp b/pcsx2/Frontend/InputManager.cpp index 7769d3b40a..4745e2f57b 100644 --- a/pcsx2/Frontend/InputManager.cpp +++ b/pcsx2/Frontend/InputManager.cpp @@ -18,6 +18,7 @@ #include "Frontend/InputSource.h" #include "Frontend/ImGuiManager.h" #include "PAD/Host/PAD.h" +#include "USB/USB.h" #include "common/StringUtil.h" #include "common/Timer.h" #include "VMManager.h" @@ -107,11 +108,13 @@ namespace InputManager static void AddHotkeyBindings(SettingsInterface& si); static void AddPadBindings(SettingsInterface& si, u32 pad, const char* default_type); + static void AddUSBBindings(SettingsInterface& si, u32 port); static void UpdateContinuedVibration(); static void GenerateRelativeMouseEvents(); static bool DoEventHook(InputBindingKey key, float value); static bool PreprocessEvent(InputBindingKey key, float value, GenericInputBinding generic_key); + static bool ProcessEvent(InputBindingKey key, float value, bool skip_button_handlers); template static void UpdateInputSourceState(SettingsInterface& si, std::unique_lock& settings_lock, InputSourceType type); @@ -158,6 +161,11 @@ static std::array(InputPointerAxis: s_pointer_state; static std::array(InputPointerAxis::Count)> s_pointer_axis_scale; +using PointerMoveCallback = std::function; +using KeyboardEventCallback = std::function; +static std::vector s_keyboard_event_callbacks; +static std::vector> s_pointer_move_callbacks; + // ------------------------------------------------------------------------ // Binding Parsing // ------------------------------------------------------------------------ @@ -260,43 +268,75 @@ bool InputManager::ParseBindingAndGetSource(const std::string_view& binding, Inp return false; } -std::string InputManager::ConvertInputBindingKeyToString(InputBindingKey key) +std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key) { - if (key.source_type == InputSourceType::Keyboard) + if (binding_type == InputBindingInfo::Type::Pointer || binding_type == InputBindingInfo::Type::Device) { - const std::optional str(ConvertHostKeyboardCodeToString(key.data)); - if (str.has_value() && !str->empty()) - return fmt::format("Keyboard/{}", str->c_str()); - } - else if (key.source_type == InputSourceType::Pointer) - { - if (key.source_subtype == InputSubclass::PointerButton) + // pointer and device bindings don't have a data part + if (key.source_type == InputSourceType::Keyboard) { - if (key.data < s_pointer_button_names.size()) - return fmt::format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_names[key.data]); - else - return fmt::format("Pointer-{}/Button{}", u32{key.source_index}, key.data); + return "Keyboard"; } - else if (key.source_subtype == InputSubclass::PointerAxis) + else if (key.source_type == InputSourceType::Pointer) { - return fmt::format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_names[key.data], - key.modifier == InputModifier::Negate ? '-' : '+'); + return GetPointerDeviceName(key.data); + } + else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast(key.source_type)]) + { + // This assumes that it always follows the Type/Binding form. + std::string keystr(s_input_sources[static_cast(key.source_type)]->ConvertKeyToString(key)); + std::string::size_type pos = keystr.find('/'); + if (pos != std::string::npos) + keystr.erase(pos); + return keystr; } } - else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast(key.source_type)]) + else { - return s_input_sources[static_cast(key.source_type)]->ConvertKeyToString(key); + if (key.source_type == InputSourceType::Keyboard) + { + const std::optional str(ConvertHostKeyboardCodeToString(key.data)); + if (str.has_value() && !str->empty()) + return fmt::format("Keyboard/{}", str->c_str()); + } + else if (key.source_type == InputSourceType::Pointer) + { + if (key.source_subtype == InputSubclass::PointerButton) + { + if (key.data < s_pointer_button_names.size()) + return fmt::format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_names[key.data]); + else + return fmt::format("Pointer-{}/Button{}", u32{key.source_index}, key.data); + } + else if (key.source_subtype == InputSubclass::PointerAxis) + { + return fmt::format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_names[key.data], + key.modifier == InputModifier::Negate ? '-' : '+'); + } + } + else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast(key.source_type)]) + { + return s_input_sources[static_cast(key.source_type)]->ConvertKeyToString(key); + } } return {}; } -std::string InputManager::ConvertInputBindingKeysToString(const InputBindingKey* keys, size_t num_keys) +std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys) { + // can't have a chord of devices/pointers + if (binding_type == InputBindingInfo::Type::Pointer || binding_type == InputBindingInfo::Type::Device) + { + // so only take the first + if (num_keys > 0) + return ConvertInputBindingKeyToString(binding_type, keys[0]); + } + std::stringstream ss; for (size_t i = 0; i < num_keys; i++) { - const std::string keystr(ConvertInputBindingKeyToString(keys[i])); + const std::string keystr(ConvertInputBindingKeyToString(binding_type, keys[i])); if (keystr.empty()) return std::string(); @@ -524,6 +564,23 @@ std::optional InputManager::ParsePointerKey(const std::string_v return std::nullopt; } +std::optional InputManager::GetIndexFromPointerBinding(const std::string_view& source) +{ + if (!StringUtil::StartsWith(source, "Pointer-")) + return std::nullopt; + + const std::optional pointer_index = StringUtil::FromChars(source.substr(8)); + if (!pointer_index.has_value() || pointer_index.value() < 0) + return std::nullopt; + + return static_cast(pointer_index.value()); +} + +std::string InputManager::GetPointerDeviceName(u32 pointer_index) +{ + return fmt::format("Pointer-{}", pointer_index); +} + // ------------------------------------------------------------------------ // Binding Enumeration // ------------------------------------------------------------------------ @@ -561,19 +618,35 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch if (type.empty() || type == "None") return; - const std::vector bind_names = PAD::GetControllerBinds(type); - if (!bind_names.empty()) + const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(type); + if (!cinfo) + return; + + for (u32 i = 0; i < cinfo->num_bindings; i++) { - for (u32 bind_index = 0; bind_index < static_cast(bind_names.size()); bind_index++) + const InputBindingInfo& bi = cinfo->bindings[i]; + + switch (bi.bind_type) { - const std::string& bind_name = bind_names[bind_index]; - const std::vector bindings(si.GetStringList(section.c_str(), bind_name.c_str())); - if (!bindings.empty()) + case InputBindingInfo::Type::Button: + case InputBindingInfo::Type::Axis: + case InputBindingInfo::Type::HalfAxis: { - // we use axes for all pad bindings to simplify things, and because they are pressure sensitive - AddBindings(bindings, - InputAxisEventHandler{[pad_index, bind_index](float value) { PAD::SetControllerState(pad_index, bind_index, value); }}); + const std::vector bindings(si.GetStringList(section.c_str(), bi.name)); + if (!bindings.empty()) + { + // we use axes for all pad bindings to simplify things, and because they are pressure sensitive + AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index](float value) { + PAD::SetControllerState(pad_index, bind_index, value); + }}); + } } + break; + + // TODO: Move vibration motors in here. + + default: + break; } } @@ -589,14 +662,13 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch } } - const PAD::VibrationCapabilities vibcaps = PAD::GetControllerVibrationCapabilities(type); - if (vibcaps != PAD::VibrationCapabilities::NoVibration) + if (cinfo->vibration_caps != PAD::VibrationCapabilities::NoVibration) { PadVibrationBinding vib; vib.pad_index = pad_index; bool has_any_bindings = false; - switch (vibcaps) + switch (cinfo->vibration_caps) { case PAD::VibrationCapabilities::LargeSmallMotors: { @@ -623,6 +695,65 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch } } +void InputManager::AddUSBBindings(SettingsInterface& si, u32 port) +{ + const std::string device(USB::GetConfigDevice(si, port)); + if (device.empty() || device == "None") + return; + + const std::string section(USBGetConfigSection(port)); + const u32 subtype = USB::GetConfigSubType(si, port, device); + for (const InputBindingInfo& bi : USB::GetDeviceBindings(device, subtype)) + { + const std::string bind_name(USB::GetConfigBindKey(device, bi.name)); + + switch (bi.bind_type) + { + case InputBindingInfo::Type::Button: + case InputBindingInfo::Type::Axis: + case InputBindingInfo::Type::HalfAxis: + { + // normal bindings + const std::vector bindings(si.GetStringList(section.c_str(), bind_name.c_str())); + if (!bindings.empty()) + { + AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index]( + float value) { USB::SetDeviceBindValue(port, bind_index, value); }}); + } + } + break; + + case InputBindingInfo::Type::Keyboard: + { + // set up to receive keyboard events + s_keyboard_event_callbacks.push_back([port, base = static_cast(bi.bind_index)](InputBindingKey key, float value) { + USB::SetDeviceBindValue(port, base + key.data, value); + }); + } + break; + + case InputBindingInfo::Type::Pointer: + { + const std::vector bindings(si.GetStringList(section.c_str(), bind_name.c_str())); + for (const std::string& binding : bindings) + { + const std::optional key(GetIndexFromPointerBinding(binding)); + if (!key.has_value()) + continue; + + s_pointer_move_callbacks.emplace_back(key.value(), [port, base = bi.bind_index](InputBindingKey key, float value) { + USB::SetDeviceBindValue(port, base + key.data, value); + }); + } + } + break; + + default: + break; + } + } +} + // ------------------------------------------------------------------------ // Event Handling // ------------------------------------------------------------------------ @@ -639,8 +770,7 @@ bool InputManager::HasAnyBindingsForSource(InputBindingKey key) for (const auto& it : s_binding_map) { const InputBindingKey& okey = it.first; - if (okey.source_type == key.source_type && okey.source_index == key.source_index && - okey.source_subtype == key.source_subtype) + if (okey.source_type == key.source_type && okey.source_index == key.source_index && okey.source_subtype == key.source_subtype) { return true; } @@ -661,7 +791,11 @@ bool InputManager::InvokeEvents(InputBindingKey key, float value, GenericInputBi // If imgui ate the event, don't fire our handlers. const bool skip_button_handlers = PreprocessEvent(key, value, generic_key); + return ProcessEvent(key, value, skip_button_handlers); +} +bool InputManager::ProcessEvent(InputBindingKey key, float value, bool skip_button_handlers) +{ // find all the bindings associated with this key const InputBindingKey masked_key = key.MaskDirection(); const auto range = s_binding_map.equal_range(masked_key); @@ -718,8 +852,7 @@ bool InputManager::InvokeEvents(InputBindingKey key, float value, GenericInputBi binding->current_mask = new_mask; // Workaround for multi-key bindings that share the same keys. - if (binding->num_keys > 1 && new_full_state && prev_full_state != new_full_state && - range.first != range.second) + if (binding->num_keys > 1 && new_full_state && prev_full_state != new_full_state && range.first != range.second) { // Because the binding map isn't ordered, we could iterate in the order of Shift+F1 and then // F1, which would mean that F1 wouldn't get cancelled and still activate. So, to handle this @@ -777,6 +910,9 @@ bool InputManager::PreprocessEvent(InputBindingKey key, float value, GenericInpu { if (ImGuiManager::ProcessHostKeyEvent(key, value)) return true; + + for (const KeyboardEventCallback& kbc : s_keyboard_event_callbacks) + kbc(key, value); } else if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerButton) { @@ -810,44 +946,66 @@ void InputManager::GenerateRelativeMouseEvents() if (value != state.last_value) { state.last_value = value; - InvokeEvents(key, value, GenericInputBinding::Unknown); + ProcessEvent(key, value, false); + } + + if (delta != 0.0f) + { + for (const std::pair& pmc : s_pointer_move_callbacks) + { + if (pmc.first == device) + pmc.second(key, delta); + } } } } } +std::pair InputManager::GetPointerAbsolutePosition(u32 index) +{ + return std::make_pair(s_host_pointer_positions[index][static_cast(InputPointerAxis::X)], + s_host_pointer_positions[index][static_cast(InputPointerAxis::Y)]); +} + void InputManager::UpdatePointerAbsolutePosition(u32 index, float x, float y) { const float dx = x - std::exchange(s_host_pointer_positions[index][static_cast(InputPointerAxis::X)], x); const float dy = y - std::exchange(s_host_pointer_positions[index][static_cast(InputPointerAxis::Y)], y); if (dx != 0.0f) - UpdatePointerRelativeDelta(index, InputPointerAxis::X, dx); + s_pointer_state[index][static_cast(InputPointerAxis::X)].delta.fetch_add( + static_cast(dx * 65536.0f), std::memory_order_release); if (dy != 0.0f) - UpdatePointerRelativeDelta(index, InputPointerAxis::Y, dy); + s_pointer_state[index][static_cast(InputPointerAxis::Y)].delta.fetch_add( + static_cast(dy * 65536.0f), std::memory_order_release); - ImGuiManager::UpdateMousePosition(x, y); + if (index == 0) + ImGuiManager::UpdateMousePosition(x, y); } void InputManager::UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input) { + s_host_pointer_positions[index][static_cast(axis)] += d; s_pointer_state[index][static_cast(axis)].delta.fetch_add(static_cast(d * 65536.0f), std::memory_order_release); + + if (index == 0 && axis <= InputPointerAxis::Y) + ImGuiManager::UpdateMousePosition(s_host_pointer_positions[0][0], s_host_pointer_positions[0][1]); } -bool InputManager::HasPointerAxisBinds() +void InputManager::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name) { - std::unique_lock lock(s_binding_map_write_lock); - for (const auto& it : s_binding_map) - { - const InputBindingKey& key = it.first; - if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerAxis && - key.data >= static_cast(InputPointerAxis::X) && key.data <= static_cast(InputPointerAxis::Y)) - { - return true; - } - } + if (VMManager::HasValidVM()) + USB::InputDeviceConnected(identifier); - return false; + Host::OnInputDeviceConnected(identifier, device_name); +} + +void InputManager::OnInputDeviceDisconnected(const std::string_view& identifier) +{ + if (VMManager::HasValidVM()) + USB::InputDeviceDisconnected(identifier); + + Host::OnInputDeviceDisconnected(identifier); } // ------------------------------------------------------------------------ @@ -1017,6 +1175,8 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind s_binding_map.clear(); s_pad_vibration_array.clear(); + s_keyboard_event_callbacks.clear(); + s_pointer_move_callbacks.clear(); // Hotkeys use the base configuration, except if the custom hotkeys option is enabled. const bool use_profile_hotkeys = si.GetBoolValue("Pad", "UseProfileHotkeyBindings", false); @@ -1035,6 +1195,26 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind 1.0f / std::max(si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(), default_scale), 1.0f); } + + for (u32 port = 0; port < USB::NUM_PORTS; port++) + AddUSBBindings(binding_si, port); + + // Check for relative mode bindings, and enable if there's anything using it. + bool has_relative_mode_bindings = !s_pointer_move_callbacks.empty(); + if (!has_relative_mode_bindings) + { + for (const auto& it : s_binding_map) + { + const InputBindingKey& key = it.first; + if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerAxis && + key.data >= static_cast(InputPointerAxis::X) && key.data <= static_cast(InputPointerAxis::Y)) + { + has_relative_mode_bindings = true; + break; + } + } + } + Host::SetRelativeMouseMode(has_relative_mode_bindings); } // ------------------------------------------------------------------------ diff --git a/pcsx2/Frontend/InputManager.h b/pcsx2/Frontend/InputManager.h index 83862a8726..5cc9dbf116 100644 --- a/pcsx2/Frontend/InputManager.h +++ b/pcsx2/Frontend/InputManager.h @@ -166,6 +166,7 @@ namespace InputManager /// Maximum number of host mouse devices. static constexpr u32 MAX_POINTER_DEVICES = 1; + static constexpr u32 MAX_POINTER_BUTTONS = 3; /// Returns a pointer to the external input source class, if present. InputSource* GetInputSourceInterface(InputSourceType type); @@ -179,6 +180,12 @@ namespace InputManager /// Parses an input class string. std::optional ParseInputSourceString(const std::string_view& str); + /// Parses a pointer device string, i.e. tells you which pointer is specified. + std::optional GetIndexFromPointerBinding(const std::string_view& str); + + /// Returns the device name for a pointer index (e.g. Pointer-0). + std::string GetPointerDeviceName(u32 pointer_index); + /// Converts a key code from a human-readable string to an identifier. std::optional ConvertHostKeyboardStringToCode(const std::string_view& str); @@ -199,10 +206,10 @@ namespace InputManager std::optional ParseInputBindingKey(const std::string_view& binding); /// Converts a input key to a string. - std::string ConvertInputBindingKeyToString(InputBindingKey key); + std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key); /// Converts a chord of binding keys to a string. - std::string ConvertInputBindingKeysToString(const InputBindingKey* keys, size_t num_keys); + std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys); /// Returns a list of all hotkeys. std::vector GetHotkeyList(); @@ -266,14 +273,20 @@ namespace InputManager /// The pad vibration state will internally remain, so that when emulation is unpaused, the effect resumes. void PauseVibration(); + /// Reads absolute pointer position. + std::pair GetPointerAbsolutePosition(u32 index); + /// Updates absolute pointer position. Can call from UI thread, use when the host only reports absolute coordinates. void UpdatePointerAbsolutePosition(u32 index, float x, float y); /// Updates relative pointer position. Can call from the UI thread, use when host supports relative coordinate reporting. void UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input = false); - /// Returns true if any bindings are present which require relative mouse movement. - bool HasPointerAxisBinds(); + /// Called when a new input device is connected. + void OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name); + + /// Called when an input device is disconnected. + void OnInputDeviceDisconnected(const std::string_view& identifier); } // namespace InputManager namespace Host @@ -286,4 +299,7 @@ namespace Host /// Called when an input device is disconnected. void OnInputDeviceDisconnected(const std::string_view& identifier); + + /// Enables relative mouse mode in the host. + void SetRelativeMouseMode(bool enabled); } // namespace Host diff --git a/pcsx2/Frontend/SDLInputSource.cpp b/pcsx2/Frontend/SDLInputSource.cpp index eb0a4462fe..9e3b4d4023 100644 --- a/pcsx2/Frontend/SDLInputSource.cpp +++ b/pcsx2/Frontend/SDLInputSource.cpp @@ -610,7 +610,7 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) m_controllers.push_back(std::move(cd)); - Host::OnInputDeviceConnected(StringUtil::StdStringFromFormat("SDL-%d", player_id), name); + InputManager::OnInputDeviceConnected(StringUtil::StdStringFromFormat("SDL-%d", player_id), name); return true; } @@ -620,7 +620,7 @@ bool SDLInputSource::CloseDevice(int joystick_index) if (it == m_controllers.end()) return false; - Host::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("SDL-%d", it->player_id)); + InputManager::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("SDL-%d", it->player_id)); if (it->haptic) SDL_HapticClose(it->haptic); diff --git a/pcsx2/Frontend/XInputSource.cpp b/pcsx2/Frontend/XInputSource.cpp index dabc1942b5..a5667f93cd 100644 --- a/pcsx2/Frontend/XInputSource.cpp +++ b/pcsx2/Frontend/XInputSource.cpp @@ -397,16 +397,15 @@ void XInputSource::HandleControllerConnection(u32 index) cd.last_state = {}; cd.last_state_scp = {}; - Host::OnInputDeviceConnected( + InputManager::OnInputDeviceConnected( StringUtil::StdStringFromFormat("XInput-%u", index), StringUtil::StdStringFromFormat("XInput Controller %u", index)); } void XInputSource::HandleControllerDisconnection(u32 index) { Console.WriteLn("XInput controller %u disconnected.", index); + InputManager::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("XInput-%u", index)); m_controllers[index] = {}; - - Host::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("XInput-%u", index)); } void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state) diff --git a/pcsx2/GS/GS.h b/pcsx2/GS/GS.h index 1363b759a6..f6ad418af7 100644 --- a/pcsx2/GS/GS.h +++ b/pcsx2/GS/GS.h @@ -20,6 +20,7 @@ #include "SaveState.h" #include "pcsx2/Config.h" #include "pcsx2/GS/config.h" +#include "gsl/span" #include @@ -87,6 +88,10 @@ void GSgetInternalResolution(int* width, int* height); void GSgetStats(std::string& info); void GSgetTitleStats(std::string& info); +/// Converts window position to normalized display coordinates (0..1). A value less than 0 or greater than 1 is +/// returned if the position lies outside the display area. +void GSTranslateWindowToDisplayCoordinates(float window_x, float window_y, float* display_x, float* display_y); + void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config); void GSSwitchRenderer(GSRendererType new_renderer); void GSResetAPIState(); diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index 96a83ca297..826c646b4b 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -71,9 +71,15 @@ static std::mutex s_screenshot_threads_mutex; std::unique_ptr g_gs_renderer; +// Since we read this on the EE thread, we can't put it in the renderer, because +// we might be switching while the other thread reads it. +static GSVector4 s_last_draw_rect; + + GSRenderer::GSRenderer() : m_shader_time_start(Common::Timer::GetCurrentValue()) { + s_last_draw_rect = GSVector4::zero(); } GSRenderer::~GSRenderer() = default; @@ -686,6 +692,7 @@ void GSRenderer::VSync(u32 field, bool registers_written) draw_rect = CalculateDrawDstRect(g_host_display->GetWindowWidth(), g_host_display->GetWindowHeight(), src_rect, current->GetSize(), g_host_display->GetDisplayAlignment(), g_host_display->UsesLowerLeftOrigin(), GetVideoMode() == GSVideoMode::SDTV_480P || (GSConfig.PCRTCOverscan && GSConfig.PCRTCOffsets)); + s_last_draw_rect = draw_rect; if (GSConfig.CASMode != GSCASMode::Disabled) { @@ -924,6 +931,7 @@ void GSRenderer::PresentCurrentFrame() const GSVector4 draw_rect(CalculateDrawDstRect(g_host_display->GetWindowWidth(), g_host_display->GetWindowHeight(), src_rect, current->GetSize(), g_host_display->GetDisplayAlignment(), g_host_display->UsesLowerLeftOrigin(), GetVideoMode() == GSVideoMode::SDTV_480P || (GSConfig.PCRTCOverscan && GSConfig.PCRTCOffsets))); + s_last_draw_rect = draw_rect; const u64 current_time = Common::Timer::GetCurrentValue(); const float shader_time = static_cast(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start)); @@ -937,6 +945,23 @@ void GSRenderer::PresentCurrentFrame() g_gs_device->RestoreAPIState(); } +void GSTranslateWindowToDisplayCoordinates(float window_x, float window_y, float* display_x, float* display_y) +{ + const float draw_width = s_last_draw_rect.z - s_last_draw_rect.x; + const float draw_height = s_last_draw_rect.w - s_last_draw_rect.y; + const float rel_x = window_x - s_last_draw_rect.x; + const float rel_y = window_y - s_last_draw_rect.y; + if (rel_x < 0 || rel_x > draw_width || rel_y < 0 || rel_y > draw_height) + { + *display_x = -1.0f; + *display_y = -1.0f; + return; + } + + *display_x = rel_x / draw_width; + *display_y = rel_y / draw_height; +} + #ifndef PCSX2_CORE bool GSRenderer::BeginCapture(std::string& filename) diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index 783ed00220..d8a507b6f4 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -21,6 +21,12 @@ #include "Gif_Unit.h" #include "SPU2/spu2.h" +#ifdef PCSX2_CORE +#include "USB/USB.h" +#else +#include "USB/USBNull.h" +#endif + #include "fmt/core.h" using namespace R5900; @@ -78,7 +84,7 @@ void hwReset() vif1Reset(); gif_fifo.init(); rcntInit(); - + USBreset(); } __fi uint intcInterrupt() diff --git a/pcsx2/IopCounters.cpp b/pcsx2/IopCounters.cpp index 4aba2606ed..0795fae4f9 100644 --- a/pcsx2/IopCounters.cpp +++ b/pcsx2/IopCounters.cpp @@ -24,7 +24,11 @@ #include "Common.h" #include "SPU2/spu2.h" #include "DEV9/DEV9.h" +#ifdef PCSX2_CORE #include "USB/USB.h" +#else +#include "USB/USBNull.h" +#endif #include "IopHw.h" #include "IopDma.h" #include "CDVD/CDVD.h" diff --git a/pcsx2/IopIrq.cpp b/pcsx2/IopIrq.cpp index 0e64cb3145..b54c3f7e79 100644 --- a/pcsx2/IopIrq.cpp +++ b/pcsx2/IopIrq.cpp @@ -15,7 +15,11 @@ #include "PrecompiledHeader.h" #include "DEV9/DEV9.h" +#ifdef PCSX2_CORE #include "USB/USB.h" +#else +#include "USB/USBNull.h" +#endif #include "IopHw.h" #include "IopDma.h" #include "Common.h" diff --git a/pcsx2/PAD/Host/PAD.cpp b/pcsx2/PAD/Host/PAD.cpp index ffe930fe27..78f7da56a1 100644 --- a/pcsx2/PAD/Host/PAD.cpp +++ b/pcsx2/PAD/Host/PAD.cpp @@ -600,12 +600,6 @@ void PAD::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& } } -PAD::VibrationCapabilities PAD::GetControllerVibrationCapabilities(const std::string_view& type) -{ - const ControllerInfo* info = GetControllerInfo(type); - return info ? info->vibration_caps : VibrationCapabilities::NoVibration; -} - static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& section, const InputManager::GenericInputBindingMapping& mapping, GenericInputBinding generic_name, const char* bind_name) diff --git a/pcsx2/PAD/Host/PAD.h b/pcsx2/PAD/Host/PAD.h index 379873929f..f2a87250e5 100644 --- a/pcsx2/PAD/Host/PAD.h +++ b/pcsx2/PAD/Host/PAD.h @@ -106,9 +106,6 @@ namespace PAD /// Returns the list of binds for the specified controller type. std::vector GetControllerBinds(const std::string_view& type); - /// Returns the vibration configuration for the specified controller type. - VibrationCapabilities GetControllerVibrationCapabilities(const std::string_view& type); - /// Returns general information for the specified controller type. const ControllerInfo* GetControllerInfo(ControllerType type); const ControllerInfo* GetControllerInfo(const std::string_view& name); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 037770425c..5e8e7a370b 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -26,7 +26,10 @@ #include "CDVD/CDVDcommon.h" #include "MemoryCardFile.h" -#ifndef PCSX2_CORE +#ifdef PCSX2_CORE +#include "USB/USB.h" +#else +#include "USB/USBNull.h" #include "gui/AppConfig.h" #include "GS/GS.h" #endif @@ -1077,6 +1080,62 @@ void Pcsx2Config::FramerateOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapEntry(SlomoScalar); } +#ifdef PCSX2_CORE + +Pcsx2Config::USBOptions::USBOptions() +{ + for (u32 i = 0; i < static_cast(Ports.size()); i++) + { + Ports[i].DeviceType = -1; + Ports[i].DeviceSubtype = 0; + } +} + +void Pcsx2Config::USBOptions::LoadSave(SettingsWrapper& wrap) +{ + for (u32 i = 0; i < static_cast(Ports.size()); i++) + { + const std::string section(USBGetConfigSection(i)); + + std::string device = USB::DeviceTypeIndexToName(Ports[i].DeviceType); + wrap.Entry(section.c_str(), "Type", device, device); + + if (wrap.IsLoading()) + Ports[i].DeviceType = USB::DeviceTypeNameToIndex(device); + + const std::string subtype_key(fmt::format("{}_subtype", USB::DeviceTypeIndexToName(Ports[i].DeviceType))); + wrap.Entry(section.c_str(), subtype_key.c_str(), Ports[i].DeviceSubtype); + } +} + +bool Pcsx2Config::USBOptions::Port::operator==(const USBOptions::Port& right) const +{ + return OpEqu(DeviceType) && OpEqu(DeviceSubtype); +} + +bool Pcsx2Config::USBOptions::Port::operator!=(const USBOptions::Port& right) const +{ + return !this->operator==(right); +} + +bool Pcsx2Config::USBOptions::operator==(const USBOptions& right) const +{ + for (u32 i = 0; i < static_cast(Ports.size()); i++) + { + if (!OpEqu(Ports[i])) + return false; + } + + return true; +} + +bool Pcsx2Config::USBOptions::operator!=(const USBOptions& right) const +{ + return !this->operator==(right); +} + +#endif + #ifdef ENABLE_ACHIEVEMENTS Pcsx2Config::AchievementsOptions::AchievementsOptions() @@ -1197,6 +1256,9 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap) Debugger.LoadSave(wrap); Trace.LoadSave(wrap); +#ifdef PCSX2_CORE + USB.LoadSave(wrap); +#endif #ifdef ENABLE_ACHIEVEMENTS Achievements.LoadSave(wrap); diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 1a6af9c3b4..7139948321 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -38,7 +38,6 @@ #include "Elfheader.h" #include "CDVD/CDVD.h" -#include "USB/USB.h" #include "Patch.h" #include "GameDatabase.h" @@ -120,9 +119,6 @@ void cpuReset() g_GameStarted = false; g_GameLoading = false; - // Probably not the right place, but it has to be done when the ram is actually initialized - USBsetRAM(iopMem->Main); - // FIXME: LastELF should be reset on media changes as well as on CPU resets, in // the very unlikely case that a user swaps to another media source that "looks" // the same (identical ELF names) but is actually different (devs actually could diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index fcc1b401c1..cd4f3bd77f 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -40,14 +40,15 @@ #include "GS.h" #include "GS/GS.h" #include "SPU2/spu2.h" -#include "USB/USB.h" #include "PAD/Gamepad.h" #ifndef PCSX2_CORE #include "gui/App.h" #include "gui/ConsoleLogger.h" #include "gui/SysThreads.h" +#include "USB/USBNull.h" #else +#include "USB/USB.h" #include "VMManager.h" #endif @@ -424,7 +425,7 @@ static int SysState_MTGSFreeze(FreezeAction mode, freezeData* fP) static constexpr SysState_Component SPU2{ "SPU2", SPU2freeze }; static constexpr SysState_Component PAD_{ "PAD", PADfreeze }; -static constexpr SysState_Component USB{ "USB", USBfreeze }; +static constexpr SysState_Component USB_{ "USB", USBfreeze }; static constexpr SysState_Component GS{ "GS", SysState_MTGSFreeze }; @@ -644,8 +645,8 @@ public: virtual ~SavestateEntry_USB() = default; const char* GetFilename() const { return "USB.bin"; } - void FreezeIn(zip_file_t* zf) const { return SysState_ComponentFreezeIn(zf, USB); } - void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOut(writer, USB); } + void FreezeIn(zip_file_t* zf) const { return SysState_ComponentFreezeIn(zf, USB_); } + void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOut(writer, USB_); } bool IsRequired() const { return false; } }; @@ -726,7 +727,7 @@ static const std::unique_ptr SavestateEntries[] = { std::unique_ptr(new SavestateEntry_VU0prog), std::unique_ptr(new SavestateEntry_VU1prog), std::unique_ptr(new SavestateEntry_SPU2), -#ifndef PCSX2_CORE +#ifdef PCSX2_CORE std::unique_ptr(new SavestateEntry_USB), #endif std::unique_ptr(new SavestateEntry_PAD), diff --git a/pcsx2/USB/USB.cpp b/pcsx2/USB/USB.cpp index d9e1bd787e..fc3a8326c0 100644 --- a/pcsx2/USB/USB.cpp +++ b/pcsx2/USB/USB.cpp @@ -20,286 +20,150 @@ #include #include "PrecompiledHeader.h" +#include "common/SettingsInterface.h" #include "common/WindowInfo.h" #include "USB.h" #include "qemu-usb/USBinternal.h" #include "qemu-usb/desc.h" -#include "shared/shared_usb.h" #include "deviceproxy.h" -#include "configuration.h" + +#include "HostSettings.h" +#include "StateWrapper.h" +#include "fmt/format.h" #define PSXCLK 36864000 /* 36.864 Mhz */ -OHCIState* qemu_ohci = NULL; -USBDevice* usb_device[2] = {NULL}; -static bool usb_opened = false; - -Config conf; -// we'll probably switch our save state system at some point to standardize in -// the core anyways -char USBfreezeID[] = "govqemUSB1"; -typedef struct +namespace USB { - char freezeID[11]; - s64 cycles; - s64 remaining; - OHCIState t; - struct + OHCIPort& GetOHCIPort(u32 port); + + static bool CreateDevice(u32 port); + static void DestroyDevice(u32 port); + static void UpdateDevice(u32 port); + + static void DoOHCIState(StateWrapper& sw); + static void DoEndpointState(USBEndpoint* ep, StateWrapper& sw); + static void DoDeviceState(USBDevice* dev, StateWrapper& sw); + static void DoPacketState(USBPacket* p, StateWrapper& sw, const std::array& valid_devices); +} // namespace USB + +static OHCIState* s_qemu_ohci = nullptr; +static USBDevice* s_usb_device[USB::NUM_PORTS] = {}; +static const DeviceProxy* s_usb_device_proxy[USB::NUM_PORTS] = {}; + +static s64 s_usb_clocks = 0; +static s64 s_usb_remaining = 0; + +int64_t g_usb_frame_time = 0; +int64_t g_usb_bit_time = 0; +int64_t g_usb_last_cycle = 0; + +std::string USBGetConfigSection(int port) +{ + return fmt::format("USB{}", port + 1); +} + +OHCIPort& USB::GetOHCIPort(u32 port) +{ + // Apparently the ports on the hub are swapped. + // Get this wrong and games like GT4 won't spin your wheelz. + const u32 rhport = (port == 0) ? 1 : 0; + return s_qemu_ohci->rhport[rhport]; +} + +bool USB::CreateDevice(u32 port) +{ + const Pcsx2Config::USBOptions::Port& portcfg = EmuConfig.USB.Ports[port]; + const DeviceProxy* proxy = RegisterDevice::instance().Device(portcfg.DeviceType); + if (!proxy) + return true; + + DevCon.WriteLn("(USB) Creating a %s in port %u", proxy->Name(), port + 1); + USBDevice* dev; { - DeviceType index; - u32 size; - USBDevice dev; - } device[2]; - - struct usb_packet - { - USBEndpoint ep; //usb packet endpoint - u32 dev_index; - u32 data_size; - } usb_packet; -} USBfreezeData; - -u8* ram = 0; -FILE* usbLog; -int64_t usb_frame_time; -int64_t usb_bit_time; - -s64 clocks = 0; -s64 remaining = 0; - -#if defined(_WIN32) -HWND gsWnd = nullptr; -#elif defined(__linux__) -#include "gtk.h" -#include -#include -Display* g_GSdsp = nullptr; -Window g_GSwin; -#endif - -Config::Config() - : Log(0) -{ -} - -//Simpler to reset and reattach after USBclose/USBopen -void Reset() -{ - if (qemu_ohci) - ohci_hard_reset(qemu_ohci); -} - -void OpenDevice(int port) -{ - //TODO Pass pDsp to open probably so dinput can bind to this HWND - if (usb_device[port] && usb_device[port]->klass.open) - usb_device[port]->klass.open(usb_device[port] /*, pDsp*/); -} - -static void CloseDevice(int port) -{ - if (usb_device[port] && usb_device[port]->klass.close) - usb_device[port]->klass.close(usb_device[port]); -} - -void DestroyDevice(int port) -{ - if (qemu_ohci && qemu_ohci->rhport[port].port.dev) - { - qemu_ohci->rhport[port].port.dev->klass.unrealize(qemu_ohci->rhport[port].port.dev); - qemu_ohci->rhport[port].port.dev = nullptr; + auto lock = Host::GetSettingsLock(); + dev = proxy->CreateDevice(*Host::GetSettingsInterface(), port, portcfg.DeviceSubtype); } - else if (usb_device[port]) - usb_device[port]->klass.unrealize(usb_device[port]); - - usb_device[port] = nullptr; -} - -void DestroyDevices() -{ - for (int i = 0; i < 2; i++) + if (!dev) { - CloseDevice(i); - DestroyDevice(i); + Console.Error("Failed to create USB device in port %u (%s)", port + 1, proxy->Name()); + return false; } + + pxAssertRel(s_qemu_ohci, "Has OHCI"); + pxAssertRel(!GetOHCIPort(port).port.dev, "No device in OHCI when creating"); + GetOHCIPort(port).port.dev = dev; + dev->attached = true; + usb_attach(&GetOHCIPort(port).port); + s_usb_device[port] = dev; + s_usb_device_proxy[port] = proxy; + return true; } -static USBDevice* CreateDevice(DeviceType index, int port) +void USB::DestroyDevice(u32 port) { - USBDevice* device = nullptr; - - if (index == DEVTYPE_NONE) - return nullptr; - - DeviceProxyBase* devProxy = RegisterDevice::instance().Device(index); - if (devProxy) - device = devProxy->CreateDevice(port); - else - Console.WriteLn(Color_Red, "Device %d: Unknown device type", 1 - port); - - if (!device) - { - } - return device; -} - -//TODO re-do sneaky attach -static void USBAttach(int port, USBDevice* dev, bool sneaky = false) -{ - if (!qemu_ohci) + USBDevice* dev = s_usb_device[port]; + if (!dev) return; - USBDevice* tmp = qemu_ohci->rhport[port].port.dev; - if (tmp) - { - if (!sneaky) - usb_detach(&qemu_ohci->rhport[port].port); - tmp->klass.unrealize(tmp); - } - - qemu_ohci->rhport[port].port.dev = dev; - if (dev) - { - dev->attached = true; - usb_attach(&qemu_ohci->rhport[port].port); //.ops->attach(&(qemu_ohci->rhport[port].port)); - } + if (dev->klass.unrealize) + dev->klass.unrealize(dev); + GetOHCIPort(port).port.dev = nullptr; + s_usb_device[port] = nullptr; + s_usb_device_proxy[port] = nullptr; } -static USBDevice* CreateDevice(const std::string& name, int port) +void USB::UpdateDevice(u32 port) { - USBDevice* device = nullptr; + if (!s_usb_device[port]) + return; - if (!name.empty()) - { - DeviceProxyBase* devProxy = RegisterDevice::instance().Device(name); - if (devProxy) - device = devProxy->CreateDevice(port); - else - Console.WriteLn(Color_Red, "Port %d: Unknown device type", port); - } - - return device; -} - -void CreateDevices() -{ - if (!qemu_ohci) - return; //No USBinit yet ie. called from config. dialog - DestroyDevices(); - - for (int i = 0; i < 2; i++) - { - usb_device[i] = CreateDevice(conf.Port[i], i); - USBAttach(i, usb_device[i]); - if (usb_opened) - OpenDevice(i); - } + auto lock = Host::GetSettingsLock(); + s_usb_device_proxy[port]->UpdateSettings(s_usb_device[port], *Host::GetSettingsInterface()); } s32 USBinit() { - USBsetSettingsDir(); - RegisterDevice::Register(); - LoadConfig(); - - if (conf.Log && !usbLog) - { -#ifdef _WIN32 - usbLog = wfopen(LogDir.c_str(), L"wb"); // L"wb,ccs=UNICODE"); -#else - usbLog = wfopen(LogDir.c_str(), "wb"); // L"wb,ccs=UNICODE"); -#endif - //if(usbLog) setvbuf(usbLog, NULL, _IONBF, 0); - } - - qemu_ohci = ohci_create(0x1f801600, 2); - if (!qemu_ohci) - return 1; - - clocks = 0; - remaining = 0; - return 0; } void USBshutdown() { - - DestroyDevices(); RegisterDevice::instance().Unregister(); - - free(qemu_ohci); - - ram = 0; - - //#ifdef _DEBUG - if (conf.Log && usbLog) - { - fclose(usbLog); - usbLog = nullptr; - } - //#endif - usb_opened = false; } -s32 USBopen(const WindowInfo& wi) +bool USBopen() { + s_qemu_ohci = ohci_create(0x1f801600, 2); + if (!s_qemu_ohci) + return false; - if (conf.Log && !usbLog) - { - usbLog = fopen("logs/usbLog.txt", "a"); - //if(usbLog) setvbuf(usbLog, NULL, _IONBF, 0); - } + s_usb_clocks = 0; + s_usb_remaining = 0; + g_usb_last_cycle = 0; - void* window_handle_for_init = nullptr; -#if defined(_WIN32) - if (wi.type == WindowInfo::Type::Win32) - { - gsWnd = static_cast(wi.window_handle); - window_handle_for_init = wi.window_handle; - } -#elif defined(__linux__) - if (wi.type == WindowInfo::Type::X11) - { - g_GSdsp = static_cast(wi.display_connection); - g_GSwin = reinterpret_cast(wi.window_handle); - window_handle_for_init = reinterpret_cast(g_GSwin); - } -#endif + for (u32 port = 0; port < USB::NUM_PORTS; port++) + USB::CreateDevice(port); - try - { - shared::Initialize(window_handle_for_init); - } - catch (std::runtime_error& e) - { - Console.WriteLn(Color_Red, "USB: %s", e.what()); - } - - if (!usb_device[0] && !usb_device[1]) - { - CreateDevices(); //TODO Pass pDsp to init? - } - - OpenDevice(0 /*, pDsp */); - OpenDevice(1 /*, pDsp */); - usb_opened = true; - return 0; + return true; } void USBclose() { - CloseDevice(0); - CloseDevice(1); - shared::Uninitialize(); - usb_opened = false; -#if defined(_WIN32) - gsWnd = {}; -#elif defined(__linux__) - g_GSdsp = nullptr; - g_GSwin = {}; -#endif + for (u32 port = 0; port < USB::NUM_PORTS; port++) + USB::DestroyDevice(port); + + free(s_qemu_ohci); + s_qemu_ohci = nullptr; +} + +void USBreset() +{ + s_usb_clocks = 0; + s_usb_remaining = 0; + g_usb_last_cycle = 0; + ohci_hard_reset(s_qemu_ohci); } u8 USBread8(u32 addr) @@ -316,7 +180,7 @@ u32 USBread32(u32 addr) { u32 hard; - hard = ohci_mem_read(qemu_ohci, addr); + hard = ohci_mem_read(s_qemu_ohci, addr); return hard; @@ -332,237 +196,311 @@ void USBwrite16(u32 addr, u16 value) void USBwrite32(u32 addr, u32 value) { - ohci_mem_write(qemu_ohci, addr, value); + ohci_mem_write(s_qemu_ohci, addr, value); } -extern u32 bits; - -void USBsetRAM(void* mem) +void USB::DoOHCIState(StateWrapper& sw) { - ram = (u8*)mem; - Reset(); + if (!sw.DoMarker("USBOHCI")) + return; + + sw.Do(&g_usb_last_cycle); + sw.Do(&s_usb_clocks); + sw.Do(&s_usb_remaining); + + sw.Do(&s_qemu_ohci->eof_timer); + sw.Do(&s_qemu_ohci->sof_time); + + sw.Do(&s_qemu_ohci->ctl); + sw.Do(&s_qemu_ohci->status); + sw.Do(&s_qemu_ohci->intr_status); + sw.Do(&s_qemu_ohci->intr); + + sw.Do(&s_qemu_ohci->hcca); + sw.Do(&s_qemu_ohci->ctrl_head); + sw.Do(&s_qemu_ohci->ctrl_cur); + sw.Do(&s_qemu_ohci->bulk_head); + sw.Do(&s_qemu_ohci->bulk_cur); + sw.Do(&s_qemu_ohci->per_cur); + sw.Do(&s_qemu_ohci->done); + sw.Do(&s_qemu_ohci->done_count); + + s_qemu_ohci->fsmps = sw.DoBitfield(s_qemu_ohci->fsmps); + s_qemu_ohci->fit = sw.DoBitfield(s_qemu_ohci->fit); + s_qemu_ohci->fi = sw.DoBitfield(s_qemu_ohci->fi); + s_qemu_ohci->frt = sw.DoBitfield(s_qemu_ohci->frt); + sw.Do(&s_qemu_ohci->frame_number); + sw.Do(&s_qemu_ohci->padding); + sw.Do(&s_qemu_ohci->pstart); + sw.Do(&s_qemu_ohci->lst); + + sw.Do(&s_qemu_ohci->rhdesc_a); + sw.Do(&s_qemu_ohci->rhdesc_b); + for (u32 i = 0; i < OHCI_MAX_PORTS; i++) + sw.Do(&s_qemu_ohci->rhport[i].ctrl); + + sw.Do(&s_qemu_ohci->old_ctl); + sw.DoArray(s_qemu_ohci->usb_buf, sizeof(s_qemu_ohci->usb_buf)); + sw.Do(&s_qemu_ohci->async_td); + sw.Do(&s_qemu_ohci->async_complete); +} + +void USB::DoDeviceState(USBDevice* dev, StateWrapper& sw) +{ + if (!sw.DoMarker("USBDevice")) + return; + + sw.Do(&dev->speed); + sw.Do(&dev->addr); + sw.Do(&dev->state); + sw.DoBytes(&dev->setup_buf, sizeof(dev->setup_buf)); + sw.DoBytes(&dev->data_buf, sizeof(dev->data_buf)); + sw.Do(&dev->remote_wakeup); + sw.Do(&dev->setup_state); + sw.Do(&dev->setup_len); + sw.Do(&dev->setup_index); + + sw.Do(&dev->configuration); + usb_desc_set_config(dev, dev->configuration); + + int altsetting[USB_MAX_INTERFACES]; + std::memcpy(altsetting, dev->altsetting, sizeof(altsetting)); + sw.DoPODArray(altsetting, std::size(altsetting)); + for (u32 i = 0; i < USB_MAX_INTERFACES; i++) + { + dev->altsetting[i] = altsetting[i]; + usb_desc_set_interface(dev, i, altsetting[i]); + } + + DoEndpointState(&dev->ep_ctl, sw); + for (u32 i = 0; i < USB_MAX_ENDPOINTS; i++) + DoEndpointState(&dev->ep_in[i], sw); + for (u32 i = 0; i < USB_MAX_ENDPOINTS; i++) + DoEndpointState(&dev->ep_out[i], sw); +} + +void USB::DoEndpointState(USBEndpoint* ep, StateWrapper& sw) +{ + // assumed the fields above are constant + sw.Do(&ep->pipeline); + sw.Do(&ep->halted); + + if (sw.IsReading()) + { + // clear out all packets, we'll fill it in later + while (!QTAILQ_EMPTY(&ep->queue)) + QTAILQ_REMOVE(&ep->queue, QTAILQ_FIRST(&ep->queue), queue); + } +} + +void USB::DoPacketState(USBPacket* p, StateWrapper& sw, const std::array& valid_devices) +{ + if (!sw.DoMarker("USBPacket")) + return; + + s32 dev_index = -1; + s32 ep_index = -1; + u32 p_iov_size = 0; + bool queued = false; + if (sw.IsWriting()) + { + USBEndpoint* ep = p->ep; + if (ep) + { + for (u32 i = 0; i < NUM_PORTS; i++) + { + USBDevice* dev = s_usb_device[i]; + if (valid_devices[i] && ep->dev == dev) + { + dev_index = static_cast(i); + if (ep == &dev->ep_ctl) + ep_index = 0; + else if (ep >= &dev->ep_in[0] && ep <= &dev->ep_in[USB_MAX_ENDPOINTS - 1]) + ep_index = static_cast(ep - &dev->ep_in[0]) + 1; + else if (ep >= &dev->ep_out[0] && ep <= &dev->ep_out[USB_MAX_ENDPOINTS - 1]) + ep_index = static_cast(ep - &dev->ep_out[0]) + 1 + USB_MAX_ENDPOINTS; + + USBPacket* pp; + QTAILQ_FOREACH(pp, &ep->queue, queue) + { + if (pp == p) + queued = true; + } + + break; + } + } + if (dev_index < 0 || ep_index < 0) + Console.Error("Failed to save USB packet from unknown endpoint"); + else + p_iov_size = p->iov.size; + } + } + + sw.Do(&dev_index); + sw.Do(&ep_index); + sw.Do(&p_iov_size); + sw.Do(&queued); + + sw.Do(&p->pid); + sw.Do(&p->id); + sw.Do(&p->stream); + sw.Do(&p->parameter); + sw.Do(&p->short_not_ok); + sw.Do(&p->int_req); + sw.Do(&p->status); + sw.Do(&p->actual_length); + sw.Do(&p->state); + + if (sw.IsReading()) + { + qemu_iovec_reset(&p->iov); + p->ep = nullptr; + + if (dev_index >= 0 && ep_index >= 0 && valid_devices[static_cast(dev_index)]) + { + USBDevice* dev = s_usb_device[static_cast(dev_index)]; + pxAssert(dev); + + if (p_iov_size > 0) + qemu_iovec_add(&p->iov, s_qemu_ohci->usb_buf, p_iov_size); + + if (ep_index == 0) + p->ep = &dev->ep_ctl; + else if (ep_index < (1 + USB_MAX_ENDPOINTS)) + p->ep = &dev->ep_in[ep_index - 1]; + else if (ep_index < (1 + USB_MAX_ENDPOINTS + USB_MAX_ENDPOINTS)) + p->ep = &dev->ep_out[ep_index - 1 - USB_MAX_ENDPOINTS]; + + if (p->ep && queued) + QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); + } + } } s32 USBfreeze(FreezeAction mode, freezeData* data) { - USBfreezeData usbd = {0}; + std::array valid_devices = {}; - //TODO FREEZE_SIZE mismatch causes loading to fail in PCSX2 beforehand if (mode == FreezeAction::Load) { - if ((long unsigned int)data->size < sizeof(USBfreezeData)) + StateWrapper::ReadOnlyMemoryStream swstream(data->data, data->size); + StateWrapper sw(&swstream, StateWrapper::Mode::Read, g_SaveVersion); + + if (!sw.DoMarker("USB")) { - Console.WriteLn(Color_Red, "USB: Unable to load freeze data! Got %d bytes, expected >= %zu.", data->size, sizeof(USBfreezeData)); - return -1; + Console.Error("USB state is invalid, resetting."); + USBreset(); + return 0; } - usbd = *(USBfreezeData*)data->data; - usbd.freezeID[10] = 0; + USB::DoOHCIState(sw); - if (strcmp(usbd.freezeID, USBfreezeID) != 0) + for (u32 port = 0; port < USB::NUM_PORTS; port++) { - Console.WriteLn(Color_Red, "USB: Unable to load freeze data! Found ID %s, expected ID %s.", usbd.freezeID, USBfreezeID); - return -1; + s32 state_devtype; + u32 state_devsubtype; + u32 state_size; + sw.Do(&state_devtype); + sw.Do(&state_devsubtype); + sw.Do(&state_size); + + // this is *assuming* the config is correct... there's no reason it shouldn't be. + if (sw.HasError() || + EmuConfig.USB.Ports[port].DeviceType != state_devtype || + EmuConfig.USB.Ports[port].DeviceSubtype != state_devsubtype || + (state_devtype != DEVTYPE_NONE && !s_usb_device[port])) + { + Console.Error("Save state has device type %u, but config has %u. Reattaching device.", state_devtype, EmuConfig.USB.Ports[port].DeviceType); + if (s_usb_device[port]) + usb_reattach(&USB::GetOHCIPort(port).port); + + sw.SkipBytes(state_size); + continue; + } + + if (!s_usb_device[port]) + { + // nothing in this port + sw.SkipBytes(state_size); + continue; + } + + USB::DoDeviceState(s_usb_device[port], sw); + + if (!s_usb_device_proxy[port]->Freeze(s_usb_device[port], sw) || sw.HasError()) + { + Console.Error("Failed to deserialize USB port %u, removing device.", port); + USB::DestroyDevice(port); + continue; + } + + valid_devices[port] = true; } - if ((long unsigned int)data->size < sizeof(USBfreezeData) + usbd.device[0].size + usbd.device[1].size + 8192) - return -1; - - //TODO Subsequent save state loadings make USB "stall" for n seconds since previous load - //clocks = usbd.cycles; - //remaining = usbd.remaining; - - CloseDevice(0); - CloseDevice(1); - - for (uint32_t i = 0; i < qemu_ohci->num_ports; i++) + USB::DoPacketState(&s_qemu_ohci->usb_packet, sw, valid_devices); + if (sw.HasError()) { - usbd.t.rhport[i].port.opaque = qemu_ohci; - usbd.t.rhport[i].port.ops = qemu_ohci->rhport[i].port.ops; - usbd.t.rhport[i].port.dev = qemu_ohci->rhport[i].port.dev; - } - //if (qemu_ohci->usb_packet.iov.iov) - usb_packet_cleanup(&qemu_ohci->usb_packet); - *qemu_ohci = usbd.t; - // restore USBPacket for OHCIState - usb_packet_init(&qemu_ohci->usb_packet); - - u8* ptr = data->data + sizeof(USBfreezeData); - RegisterDevice& regInst = RegisterDevice::instance(); - for (int i = 0; i < 2; i++) - { - auto index = regInst.Index(conf.Port[i]); - auto proxy = regInst.Device(index); - - //TODO FREEZE_SIZE mismatch causes loading to fail in PCSX2 beforehand - // but just in case, recreate the same device type as was saved - if (usbd.device[i].index != index) - { - index = usbd.device[i].index; - DestroyDevice(i); - conf.Port[i].clear(); - - proxy = regInst.Device(index); - if (proxy) - { - // re-create with saved device type - conf.Port[i] = proxy->TypeName(); - usb_device[i] = CreateDevice(index, i); - USBAttach(i, usb_device[i], index != DEVTYPE_MSD); - } - } - - if (proxy && usb_device[i]) /* usb device creation may have failed for some reason */ - { - if (proxy->Freeze(FreezeAction::Size, usb_device[i], nullptr) != (s32)usbd.device[i].size) - { - Console.WriteLn(Color_Red, "USB: Port %d: device's freeze size doesn't match.", i); - return -1; - } - - const USBDevice& tmp = usbd.device[i].dev; - - usb_device[i]->addr = tmp.addr; - usb_device[i]->attached = tmp.attached; - usb_device[i]->auto_attach = tmp.auto_attach; - usb_device[i]->configuration = tmp.configuration; - usb_device[i]->ninterfaces = tmp.ninterfaces; - usb_device[i]->flags = tmp.flags; - usb_device[i]->state = tmp.state; - usb_device[i]->remote_wakeup = tmp.remote_wakeup; - usb_device[i]->setup_state = tmp.setup_state; - usb_device[i]->setup_len = tmp.setup_len; - usb_device[i]->setup_index = tmp.setup_index; - - memcpy(usb_device[i]->data_buf, tmp.data_buf, sizeof(tmp.data_buf)); - memcpy(usb_device[i]->setup_buf, tmp.setup_buf, sizeof(tmp.setup_buf)); - - usb_desc_set_config(usb_device[i], tmp.configuration); - for (int k = 0; k < 16; k++) - { - usb_device[i]->altsetting[k] = tmp.altsetting[k]; - usb_desc_set_interface(usb_device[i], k, tmp.altsetting[k]); - } - - proxy->Freeze(FreezeAction::Load, usb_device[i], ptr); - if (!usb_device[i]->attached) - { // FIXME FREEZE_SAVE fcked up - usb_device[i]->attached = true; - usb_device_reset(usb_device[i]); - //TODO reset port if save state's and configured wheel types are different - usb_detach(&qemu_ohci->rhport[i].port); - usb_attach(&qemu_ohci->rhport[i].port); - } - OpenDevice(i); - } - else if (!proxy && index != DEVTYPE_NONE) - { - Console.WriteLn(Color_Red, "USB: Port %d: unknown device.\nUSB is probably too old for this save.", i); - } - ptr += usbd.device[i].size; - } - - u32 dev_index = usbd.usb_packet.dev_index; - - if (dev_index < countof(usb_device) && usb_device[dev_index]) - { - USBPacket* p = &qemu_ohci->usb_packet; - p->actual_length = usbd.usb_packet.data_size; - - QEMUIOVector* iov = p->combined ? &p->combined->iov : &p->iov; - iov_from_buf(iov->iov, iov->niov, 0, ptr, p->actual_length); - - if (usbd.usb_packet.ep.pid == USB_TOKEN_SETUP) - { - if (usb_device[dev_index]->ep_ctl.ifnum == usbd.usb_packet.ep.ifnum) - qemu_ohci->usb_packet.ep = &usb_device[dev_index]->ep_ctl; - } - else - { - USBEndpoint* eps = nullptr; - if (usbd.usb_packet.ep.pid == USB_TOKEN_IN) - eps = usb_device[dev_index]->ep_in; - else //if (usbd.ep.pid == USB_TOKEN_OUT) - eps = usb_device[dev_index]->ep_out; - - for (int k = 0; k < USB_MAX_ENDPOINTS; k++) - { - - if (usbd.usb_packet.ep.type == eps[k].type && usbd.usb_packet.ep.nr == eps[k].nr && usbd.usb_packet.ep.ifnum == eps[k].ifnum && usbd.usb_packet.ep.pid == eps[k].pid) - { - qemu_ohci->usb_packet.ep = &eps[k]; - break; - } - } - } + Console.WriteLn("Failed to read USB packet, resetting all devices."); + USBreset(); + return 0; } } - //TODO straight copying of structs can break cross-platform/cross-compiler save states 'cause padding 'n' stuff else if (mode == FreezeAction::Save) { - memset(data->data, 0, data->size); //maybe it already is... - RegisterDevice& regInst = RegisterDevice::instance(); - usbd.usb_packet.dev_index = -1; + std::memset(data->data, 0, data->size); - for (int i = 0; i < 2; i++) + StateWrapper::MemoryStream swstream(data->data, data->size); + StateWrapper sw(&swstream, StateWrapper::Mode::Write, g_SaveVersion); + + if (!sw.DoMarker("USB")) + return -1; + + USB::DoOHCIState(sw); + + for (u32 port = 0; port < USB::NUM_PORTS; port++) { - //TODO check that current created usb device and conf.Port[n] are the same - auto index = regInst.Index(conf.Port[i]); - auto proxy = regInst.Device(index); - usbd.device[i].index = index; + s32 state_devtype = EmuConfig.USB.Ports[port].DeviceType; + u32 state_devsubtype = EmuConfig.USB.Ports[port].DeviceSubtype; + sw.Do(&state_devtype); + sw.Do(&state_devsubtype); - if (proxy && usb_device[i]) - usbd.device[i].size = proxy->Freeze(FreezeAction::Size, usb_device[i], nullptr); - else - usbd.device[i].size = 0; + const u32 size_pos = swstream.GetPosition(); + u32 state_size = 0; + sw.Do(&state_size); - if (qemu_ohci->usb_packet.ep && qemu_ohci->usb_packet.ep->dev == usb_device[i]) - usbd.usb_packet.dev_index = i; - } + if (sw.HasError()) + return -1; - strncpy(usbd.freezeID, USBfreezeID, strlen(USBfreezeID)); - usbd.t = *qemu_ohci; - usbd.t.usb_packet.iov = {}; - usbd.t.usb_packet.ep = nullptr; - if (qemu_ohci->usb_packet.ep) - usbd.usb_packet.ep = *qemu_ohci->usb_packet.ep; - - for (uint32_t i = 0; i < qemu_ohci->num_ports; i++) - { - usbd.t.rhport[i].port.opaque = nullptr; - usbd.t.rhport[i].port.ops = nullptr; - usbd.t.rhport[i].port.dev = nullptr; - } - - usbd.cycles = clocks; - usbd.remaining = remaining; - - u8* ptr = data->data + sizeof(USBfreezeData); - - // Save the state of the attached devices - for (int i = 0; i < 2; i++) - { - auto proxy = regInst.Device(conf.Port[i]); - if (usb_device[i]) + if (!s_usb_device[port]) { - usbd.device[i].dev = *usb_device[i]; - if (proxy && usbd.device[i].size) - proxy->Freeze(FreezeAction::Save, usb_device[i], ptr); + // nothing in this port + continue; } - memset(&usbd.device[i].dev.klass, 0, sizeof(USBDeviceClass)); - ptr += usbd.device[i].size; + const u32 start_pos = swstream.GetPosition(); + USB::DoDeviceState(s_usb_device[port], sw); + if (!s_usb_device_proxy[port]->Freeze(s_usb_device[port], sw) || sw.HasError()) + { + Console.Error("Failed to serialize USB port %u.", port); + return -1; + } + + const u32 end_pos = swstream.GetPosition(); + state_size = end_pos - start_pos; + if (!swstream.SeekAbsolute(size_pos) || (sw.Do(&state_size), sw.HasError()) || !swstream.SeekAbsolute(end_pos)) + return -1; + + valid_devices[port] = true; } - USBPacket* p = &qemu_ohci->usb_packet; - usbd.usb_packet.data_size = p->actual_length; - QEMUIOVector* iov = p->combined ? &p->combined->iov : &p->iov; - iov_to_buf(iov->iov, iov->niov, 0, ptr, p->actual_length); - - *(USBfreezeData*)data->data = usbd; + USB::DoPacketState(&s_qemu_ohci->usb_packet, sw, valid_devices); + if (sw.HasError()) + return -1; } else if (mode == FreezeAction::Size) { + // I don't like this, but until we move everything over to state wrapper, it'll have to do. data->size = 0x10000; } @@ -571,31 +509,31 @@ s32 USBfreeze(FreezeAction mode, freezeData* data) void USBasync(u32 cycles) { - remaining += cycles; - clocks += remaining; - if (qemu_ohci->eof_timer > 0) + s_usb_remaining += cycles; + s_usb_clocks += s_usb_remaining; + if (s_qemu_ohci->eof_timer > 0) { - while ((uint64_t)remaining >= qemu_ohci->eof_timer) + while ((uint64_t)s_usb_remaining >= s_qemu_ohci->eof_timer) { - remaining -= qemu_ohci->eof_timer; - qemu_ohci->eof_timer = 0; - ohci_frame_boundary(qemu_ohci); + s_usb_remaining -= s_qemu_ohci->eof_timer; + s_qemu_ohci->eof_timer = 0; + ohci_frame_boundary(s_qemu_ohci); /* * Break out of the loop if bus was stopped. * If ohci_frame_boundary hits an UE, but doesn't stop processing, * it seems to cause a hang inside the game instead. */ - if (!qemu_ohci->eof_timer) + if (!s_qemu_ohci->eof_timer) break; } - if ((remaining > 0) && (qemu_ohci->eof_timer > 0)) + if ((s_usb_remaining > 0) && (s_qemu_ohci->eof_timer > 0)) { - s64 m = qemu_ohci->eof_timer; - if (remaining < m) - m = remaining; - qemu_ohci->eof_timer -= m; - remaining -= m; + s64 m = s_qemu_ohci->eof_timer; + if (s_usb_remaining < m) + m = s_usb_remaining; + s_qemu_ohci->eof_timer -= m; + s_usb_remaining -= m; } } //if(qemu_ohci->eof_timer <= 0) @@ -604,29 +542,226 @@ void USBasync(u32 cycles) //} } -int cpu_physical_memory_rw(u32 addr, u8* buf, size_t len, int is_write) -{ - // invalid address, reset and try again - if ((u64)addr + len >= 0x200000) - { - if (qemu_ohci) - ohci_soft_reset(qemu_ohci); - return 1; - } - - if (is_write) - memcpy(&(ram[addr]), buf, len); - else - memcpy(buf, &(ram[addr]), len); - return 0; -} - -int get_ticks_per_second() +int usb_get_ticks_per_second() { return PSXCLK; } -s64 get_clock() +s64 usb_get_clock() { - return clocks; + return s_usb_clocks; +} + +s32 USB::DeviceTypeNameToIndex(const std::string_view& device) +{ + RegisterDevice& rd = RegisterDevice::instance(); + return rd.Index(device); +} + +const char* USB::DeviceTypeIndexToName(s32 device) +{ + RegisterDevice& rd = RegisterDevice::instance(); + const DeviceProxy* proxy = rd.Device(device); + return proxy ? proxy->TypeName() : "None"; +} + +std::vector> USB::GetDeviceTypes() +{ + RegisterDevice& rd = RegisterDevice::instance(); + std::vector> ret; + ret.reserve(rd.Map().size()); + for (const auto& it : rd.Map()) + ret.emplace_back(it.second->TypeName(), it.second->Name()); + return ret; +} + +const char* USB::GetDeviceName(const std::string_view& device) +{ + const DeviceProxy* dev = RegisterDevice::instance().Device(device); + return dev ? dev->Name() : "Not Connected"; +} + +std::vector USB::GetDeviceSubtypes(const std::string_view& device) +{ + const DeviceProxy* dev = RegisterDevice::instance().Device(device); + return dev ? dev->SubTypes() : std::vector(); +} + +gsl::span USB::GetDeviceBindings(const std::string_view& device, u32 subtype) +{ + const DeviceProxy* dev = RegisterDevice::instance().Device(device); + return dev ? dev->Bindings(subtype) : gsl::span(); +} + +gsl::span USB::GetDeviceSettings(const std::string_view& device, u32 subtype) +{ + const DeviceProxy* dev = RegisterDevice::instance().Device(device); + return dev ? dev->Settings(subtype) : gsl::span(); +} + +gsl::span USB::GetDeviceBindings(u32 port) +{ + pxAssert(port < NUM_PORTS); + if (s_usb_device_proxy[port]) + return s_usb_device_proxy[port]->Bindings(EmuConfig.USB.Ports[port].DeviceSubtype); + else + return {}; +} + +float USB::GetDeviceBindValue(u32 port, u32 bind_index) +{ + pxAssert(port < NUM_PORTS); + if (!s_usb_device[port]) + return 0.0f; + + return s_usb_device_proxy[port]->GetBindingValue(s_usb_device[port], bind_index); +} + +void USB::SetDeviceBindValue(u32 port, u32 bind_index, float value) +{ + pxAssert(port < NUM_PORTS); + if (!s_usb_device[port]) + return; + + s_usb_device_proxy[port]->SetBindingValue(s_usb_device[port], bind_index, value); +} + +void USB::InputDeviceConnected(const std::string_view& identifier) +{ + for (u32 i = 0; i < NUM_PORTS; i++) + { + if (s_usb_device[i]) + s_usb_device_proxy[i]->InputDeviceConnected(s_usb_device[i], identifier); + } +} + +void USB::InputDeviceDisconnected(const std::string_view& identifier) +{ + for (u32 i = 0; i < NUM_PORTS; i++) + { + if (s_usb_device[i]) + s_usb_device_proxy[i]->InputDeviceDisconnected(s_usb_device[i], identifier); + } +} + +std::string USB::GetConfigDevice(const SettingsInterface& si, u32 port) +{ + return si.GetStringValue(USBGetConfigSection(port).c_str(), "Type", "None"); +} + +u32 USB::GetConfigSubType(const SettingsInterface& si, u32 port, const std::string_view& devname) +{ + return si.GetUIntValue(USBGetConfigSection(port).c_str(), fmt::format("{}_subtype", devname).c_str(), 0u); +} + +std::string USB::GetConfigBindKey(const std::string_view& device, const std::string_view& bind_name) +{ + return fmt::format("{}_{}", device, bind_name); +} + +bool USB::GetConfigBool(SettingsInterface& si, u32 port, const char* devname, const char* key, bool default_value) +{ + const std::string real_key(fmt::format("{}_{}", devname, key)); + return si.GetBoolValue(USBGetConfigSection(port).c_str(), real_key.c_str(), default_value); +} + +s32 USB::GetConfigInt(SettingsInterface& si, u32 port, const char* devname, const char* key, s32 default_value) +{ + const std::string real_key(fmt::format("{}_{}", devname, key)); + return si.GetIntValue(USBGetConfigSection(port).c_str(), real_key.c_str(), default_value); +} + +float USB::GetConfigFloat(SettingsInterface& si, u32 port, const char* devname, const char* key, float default_value) +{ + const std::string real_key(fmt::format("{}_{}", devname, key)); + return si.GetFloatValue(USBGetConfigSection(port).c_str(), real_key.c_str(), default_value); +} + + +std::string USB::GetConfigString(SettingsInterface& si, u32 port, const char* devname, const char* key, const char* default_value /*= ""*/) +{ + const std::string real_key(fmt::format("{}_{}", devname, key)); + return si.GetStringValue(USBGetConfigSection(port).c_str(), real_key.c_str(), default_value); +} + + +static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& section, const std::string& type, + const std::vector>& mapping, GenericInputBinding generic_name, + const char* bind_name) +{ + // find the mapping it corresponds to + const std::string* found_mapping = nullptr; + for (const std::pair& it : mapping) + { + if (it.first == generic_name) + { + found_mapping = &it.second; + break; + } + } + + const std::string key(USB::GetConfigBindKey(type, bind_name)); + if (found_mapping) + { + Console.WriteLn("(MapDevice) Map %s/%s to '%s'", section.c_str(), bind_name, found_mapping->c_str()); + si.SetStringValue(section.c_str(), key.c_str(), found_mapping->c_str()); + return 1; + } + else + { + si.DeleteValue(section.c_str(), key.c_str()); + return 0; + } +} + +bool USB::MapDevice(SettingsInterface& si, u32 port, const std::vector>& mapping) +{ + const std::string section(USBGetConfigSection(port)); + const std::string type(GetConfigDevice(si, port)); + const u32 subtype = GetConfigSubType(si, port, type); + const DeviceProxy* dev = RegisterDevice::instance().Device(type); + if (!dev) + return false; + + u32 num_mappings = 0; + for (const InputBindingInfo& bi : dev->Bindings(subtype)) + { + if (bi.generic_mapping == GenericInputBinding::Unknown) + continue; + + num_mappings += TryMapGenericMapping(si, section, type, mapping, bi.generic_mapping, bi.name); + } + + return (num_mappings > 0); +} + +void USB::ClearPortBindings(SettingsInterface& si, u32 port) +{ + const std::string section(USBGetConfigSection(port)); + const std::string type(GetConfigDevice(si, port)); + const u32 subtype = GetConfigSubType(si, port, type); + const DeviceProxy* dev = RegisterDevice::instance().Device(type); + if (!dev) + return; + + for (const InputBindingInfo& bi : dev->Bindings(subtype)) + si.DeleteValue(section.c_str(), GetConfigBindKey(type, bi.name).c_str()); +} + +void USB::CheckForConfigChanges(const Pcsx2Config& old_config) +{ + static_assert(Pcsx2Config::USBOptions::NUM_PORTS == NUM_PORTS); + + for (u32 port = 0; port < NUM_PORTS; port++) + { + if (EmuConfig.USB.Ports[port] == old_config.USB.Ports[port]) + { + UpdateDevice(port); + continue; + } + + if (s_usb_device[port]) + DestroyDevice(port); + CreateDevice(port); + } } diff --git a/pcsx2/USB/USB.h b/pcsx2/USB/USB.h index bc9e5c4b60..5be5db0f1b 100644 --- a/pcsx2/USB/USB.h +++ b/pcsx2/USB/USB.h @@ -15,32 +15,85 @@ #pragma once -#include -#include +#include #include -#include +#include +#include +#include +#include "gsl/span" + +#include "Config.h" #include "SaveState.h" +class SettingsInterface; + +namespace USB +{ + enum : u32 + { + NUM_PORTS = 2, + }; + + s32 DeviceTypeNameToIndex(const std::string_view& device); + const char* DeviceTypeIndexToName(s32 device); + + std::vector> GetDeviceTypes(); + const char* GetDeviceName(const std::string_view& device); + std::vector GetDeviceSubtypes(const std::string_view& device); + gsl::span GetDeviceBindings(const std::string_view& device, u32 subtype); + gsl::span GetDeviceSettings(const std::string_view& device, u32 subtype); + + gsl::span GetDeviceBindings(u32 port); + float GetDeviceBindValue(u32 port, u32 bind_index); + void SetDeviceBindValue(u32 port, u32 bind_index, float value); + + /// Called when a new input device is connected. + void InputDeviceConnected(const std::string_view& identifier); + + /// Called when an input device is disconnected. + void InputDeviceDisconnected(const std::string_view& identifier); + + std::string GetConfigDevice(const SettingsInterface& si, u32 port); + u32 GetConfigSubType(const SettingsInterface& si, u32 port, const std::string_view& devname); + + /// Returns the configuration key for the specified bind and device type. + std::string GetConfigBindKey(const std::string_view& device, const std::string_view& bind_name); + + /// Performs automatic controller mapping with the provided list of generic mappings. + bool MapDevice(SettingsInterface& si, u32 port, const std::vector>& mapping); + + /// Clears all bindings for a given port. + void ClearPortBindings(SettingsInterface& si, u32 port); + + /// Identifies any device/subtype changes and recreates devices. + void CheckForConfigChanges(const Pcsx2Config& old_config); + + /// Reads a device-specific configuration boolean. + bool GetConfigBool(SettingsInterface& si, u32 port, const char* devname, const char* key, bool default_value); + + /// Reads a device-specific configuration integer. + s32 GetConfigInt(SettingsInterface& si, u32 port, const char* devname, const char* key, s32 default_value); + + /// Reads a device-specific configuration floating-point value. + float GetConfigFloat(SettingsInterface& si, u32 port, const char* devname, const char* key, float default_value); + + /// Reads a device-specific configuration string. + std::string GetConfigString(SettingsInterface& si, u32 port, const char* devname, const char* key, const char* default_value = ""); +} // namespace USB + +std::string USBGetConfigSection(int port); + struct WindowInfo; // --------------------------------------------------------------------- -#define USBdefs - -extern u8* ram; - -// --------------------------------------------------------------------- - -void USBconfigure(); - -void DestroyDevices(); -void CreateDevices(); s32 USBinit(); void USBasync(u32 cycles); void USBshutdown(); void USBclose(); -s32 USBopen(const WindowInfo& wi); +bool USBopen(); +void USBreset(); s32 USBfreeze(FreezeAction mode, freezeData* data); u8 USBread8(u32 addr); @@ -51,12 +104,3 @@ void USBwrite16(u32 addr, u16 value); void USBwrite32(u32 addr, u32 value); void USBsetRAM(void* mem); - -extern FILE* usbLog; -s64 get_clock(); - -/* usb-pad-raw.cpp */ -#if _WIN32 -#include "common/RedtapeWindows.h" -extern HWND gsWnd; -#endif diff --git a/pcsx2/USB/USBNull.cpp b/pcsx2/USB/USBNull.cpp index bee5ec834b..9c7d7b5695 100644 --- a/pcsx2/USB/USBNull.cpp +++ b/pcsx2/USB/USBNull.cpp @@ -15,19 +15,15 @@ #include "PrecompiledHeader.h" -#include "USB.h" - -u8* ram = nullptr; +#include "USBNull.h" void USBconfigure() {} -void DestroyDevices() {} -void CreateDevices() {} - s32 USBinit() { return 0; } void USBasync(u32 cycles) {} void USBshutdown() {} void USBclose() {} +void USBreset() {} s32 USBopen(const WindowInfo& wi) { return 0; } s32 USBfreeze(FreezeAction mode, freezeData* data) { return 0; } @@ -37,8 +33,3 @@ u32 USBread32(u32 addr) { return 0; } void USBwrite8(u32 addr, u8 value) {} void USBwrite16(u32 addr, u16 value) {} void USBwrite32(u32 addr, u32 value) {} - -void USBsetRAM(void* mem) { ram = static_cast(mem); } - -FILE* usbLog = nullptr; -s64 get_clock() { return 0; }; diff --git a/pcsx2/USB/linux/util.h b/pcsx2/USB/USBNull.h similarity index 60% rename from pcsx2/USB/linux/util.h rename to pcsx2/USB/USBNull.h index 6fda7cda24..2148c002a7 100644 --- a/pcsx2/USB/linux/util.h +++ b/pcsx2/USB/USBNull.h @@ -14,7 +14,29 @@ */ #pragma once -#include -bool file_exists(std::string path); -bool dir_exists(std::string path); +#include +#include +#include +#include + +#include "SaveState.h" + +struct WindowInfo; + +void USBconfigure(); + +s32 USBinit(); +void USBasync(u32 cycles); +void USBshutdown(); +void USBclose(); +void USBreset(); +s32 USBopen(const WindowInfo& wi); +s32 USBfreeze(FreezeAction mode, freezeData* data); + +u8 USBread8(u32 addr); +u16 USBread16(u32 addr); +u32 USBread32(u32 addr); +void USBwrite8(u32 addr, u8 value); +void USBwrite16(u32 addr, u16 value); +void USBwrite32(u32 addr, u32 value); diff --git a/pcsx2/USB/Win32/Config_usb.cpp b/pcsx2/USB/Win32/Config_usb.cpp deleted file mode 100644 index 4c57fad3ac..0000000000 --- a/pcsx2/USB/Win32/Config_usb.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "gui/AppCoreThread.h" -#include "USB/USB.h" -#include "resource_usb.h" -#include "Config_usb.h" -#include "USB/deviceproxy.h" -#include "USB/usb-pad/padproxy.h" -#include "USB/usb-mic/audiodeviceproxy.h" -#include "USB/configuration.h" -#include "USB/shared/inifile_usb.h" - -HINSTANCE hInstUSB; - -void SysMessageA(const char* fmt, ...) -{ - va_list list; - char tmp[512]; - - va_start(list, fmt); - vsprintf_s(tmp, 512, fmt, list); - va_end(list); - MessageBoxA(0, tmp, "USB Msg", 0); -} - -void SysMessageW(const wchar_t* fmt, ...) -{ - va_list list; - wchar_t tmp[512]; - - va_start(list, fmt); - vswprintf_s(tmp, 512, fmt, list); - va_end(list); - MessageBoxW(0, tmp, L"USB Msg", 0); -} - -void SelChangedAPI(HWND hW, int port) -{ - int sel = SendDlgItemMessage(hW, port ? IDC_COMBO_API1_USB : IDC_COMBO_API2_USB, CB_GETCURSEL, 0, 0); - int devtype = SendDlgItemMessage(hW, port ? IDC_COMBO1_USB : IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - if (devtype == 0) - return; - devtype--; - auto& rd = RegisterDevice::instance(); - auto devName = rd.Name(devtype); - auto apis = rd.Device(devtype)->ListAPIs(); - auto it = apis.begin(); - std::advance(it, sel); - changedAPIs[std::make_pair(port, devName)] = *it; -} - -void SelChangedSubtype(HWND hW, int port) -{ - int sel = SendDlgItemMessage(hW, port ? IDC_COMBO_WHEEL_TYPE1_USB : IDC_COMBO_WHEEL_TYPE2_USB, CB_GETCURSEL, 0, 0); - int devtype = SendDlgItemMessage(hW, port ? IDC_COMBO1_USB : IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - if (devtype == 0) - return; - devtype--; - auto& rd = RegisterDevice::instance(); - auto devName = rd.Name(devtype); - changedSubtype[std::make_pair(port, devName)] = sel; -} - -void PopulateAPIs(HWND hW, int port) -{ - SendDlgItemMessage(hW, port ? IDC_COMBO_API1_USB : IDC_COMBO_API2_USB, CB_RESETCONTENT, 0, 0); - int devtype = SendDlgItemMessage(hW, port ? IDC_COMBO1_USB : IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - if (devtype == 0) - return; - devtype--; - auto& rd = RegisterDevice::instance(); - auto dev = rd.Device(devtype); - auto devName = rd.Name(devtype); - auto apis = dev->ListAPIs(); - - std::string selApi = GetSelectedAPI(std::make_pair(port, devName)); - - std::string var; - std::wstring tmp; - if (!LoadSetting(nullptr, port, rd.Name(devtype), N_DEVICE_API, tmp)) - { - if (apis.begin() != apis.end()) - { - selApi = *apis.begin(); - changedAPIs[std::make_pair(port, devName)] = selApi; - } - } - - var = wstr_to_str(tmp); - int i = 0, sel = 0; - for (auto& api : apis) - { - auto name = dev->LongAPIName(api); - if (!name) - continue; - SendDlgItemMessageW(hW, port ? IDC_COMBO_API1_USB : IDC_COMBO_API2_USB, CB_ADDSTRING, 0, (LPARAM)name); - if (api == var) - sel = i; - i++; - } - SendDlgItemMessage(hW, port ? IDC_COMBO_API1_USB : IDC_COMBO_API2_USB, CB_SETCURSEL, sel, 0); -} - -void PopulateSubType(HWND hW, int port) -{ - SendDlgItemMessage(hW, port ? IDC_COMBO_WHEEL_TYPE1_USB : IDC_COMBO_WHEEL_TYPE2_USB, CB_RESETCONTENT, 0, 0); - int devtype = SendDlgItemMessage(hW, port ? IDC_COMBO1_USB : IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - if (devtype == 0) - return; - devtype--; - auto& rd = RegisterDevice::instance(); - auto dev = rd.Device(devtype); - auto devName = rd.Name(devtype); - - int sel = 0; - if (!LoadSetting(nullptr, port, dev->TypeName(), N_DEV_SUBTYPE, sel)) - { - changedSubtype[std::make_pair(port, devName)] = sel; - } - - for (auto subtype : dev->SubTypes()) - { - SendDlgItemMessageA(hW, port ? IDC_COMBO_WHEEL_TYPE1_USB : IDC_COMBO_WHEEL_TYPE2_USB, CB_ADDSTRING, 0, (LPARAM)subtype.c_str()); - } - SendDlgItemMessage(hW, port ? IDC_COMBO_WHEEL_TYPE1_USB : IDC_COMBO_WHEEL_TYPE2_USB, CB_SETCURSEL, sel, 0); -} - -BOOL CALLBACK ConfigureDlgProcUSB(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - - int port; - switch (uMsg) - { - case WM_INITDIALOG: - LoadConfig(); - CheckDlgButton(hW, IDC_LOGGING_USB, conf.Log); - //Selected emulated devices. - SendDlgItemMessageA(hW, IDC_COMBO1_USB, CB_ADDSTRING, 0, (LPARAM) "None"); - SendDlgItemMessageA(hW, IDC_COMBO2_USB, CB_ADDSTRING, 0, (LPARAM) "None"); - - { - auto& rd = RegisterDevice::instance(); - int i = 0, p1 = 0, p2 = 0; - for (auto& name : rd.Names()) - { - i++; //jump over "None" - auto dev = rd.Device(name); - SendDlgItemMessageW(hW, IDC_COMBO1_USB, CB_ADDSTRING, 0, (LPARAM)dev->Name()); - SendDlgItemMessageW(hW, IDC_COMBO2_USB, CB_ADDSTRING, 0, (LPARAM)dev->Name()); - - //Port 1 aka device/player 1 - if (conf.Port[1] == name) - p1 = i; - //Port 0 aka device/player 2 - if (conf.Port[0] == name) - p2 = i; - } - SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_SETCURSEL, p1, 0); - SendDlgItemMessage(hW, IDC_COMBO2_USB, CB_SETCURSEL, p2, 0); - PopulateAPIs(hW, 0); - PopulateAPIs(hW, 1); - PopulateSubType(hW, 0); - PopulateSubType(hW, 1); - } - - return TRUE; - break; - case WM_COMMAND: - switch (HIWORD(wParam)) - { - case CBN_SELCHANGE: - switch (LOWORD(wParam)) - { - case IDC_COMBO_API1_USB: - case IDC_COMBO_API2_USB: - port = (LOWORD(wParam) == IDC_COMBO_API1_USB) ? 1 : 0; - SelChangedAPI(hW, port); - break; - case IDC_COMBO1_USB: - case IDC_COMBO2_USB: - port = (LOWORD(wParam) == IDC_COMBO1_USB) ? 1 : 0; - PopulateAPIs(hW, port); - PopulateSubType(hW, port); - break; - case IDC_COMBO_WHEEL_TYPE1_USB: - case IDC_COMBO_WHEEL_TYPE2_USB: - port = (LOWORD(wParam) == IDC_COMBO_WHEEL_TYPE1_USB) ? 1 : 0; - SelChangedSubtype(hW, port); - break; - } - break; - case BN_CLICKED: - switch (LOWORD(wParam)) - { - case IDC_CONFIGURE1_USB: - case IDC_CONFIGURE2_USB: - { - LRESULT devtype, apitype; - port = (LOWORD(wParam) == IDC_CONFIGURE1_USB) ? 1 : 0; - devtype = SendDlgItemMessage(hW, port ? IDC_COMBO1_USB : IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - apitype = SendDlgItemMessage(hW, port ? IDC_COMBO_API1_USB : IDC_COMBO_API2_USB, CB_GETCURSEL, 0, 0); - - if (devtype > 0) - { - devtype--; - auto device = RegisterDevice::instance().Device(devtype); - if (device) - { - auto list = device->ListAPIs(); - auto it = list.begin(); - std::advance(it, apitype); - if (it == list.end()) - break; - std::string api = *it; - Win32Handles handles(hInstUSB, hW); - if (device->Configure(port, api, &handles) == RESULT_FAILED) - SysMessage(TEXT("Some settings may not have been saved!\n")); - } - } - } - break; - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - case IDOK: - conf.Log = IsDlgButtonChecked(hW, IDC_LOGGING_USB); - { - auto& regInst = RegisterDevice::instance(); - int i; - //device type - i = SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_GETCURSEL, 0, 0); - conf.Port[1] = regInst.Name(i - 1); - i = SendDlgItemMessage(hW, IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - conf.Port[0] = regInst.Name(i - 1); - } - - SaveConfig(); - CreateDevices(); - EndDialog(hW, RESULT_OK); - return TRUE; - } - } - } - - return FALSE; -} - -void USBconfigure() -{ - ScopedCoreThreadPause paused_core; - USBsetSettingsDir(); - RegisterDevice::Register(); - DialogBox(hInstUSB, - MAKEINTRESOURCE(IDD_CONFIG_USB), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProcUSB); - paused_core.AllowResume(); -} diff --git a/pcsx2/USB/Win32/Config_usb.h b/pcsx2/USB/Win32/Config_usb.h deleted file mode 100644 index 9259d8bc0e..0000000000 --- a/pcsx2/USB/Win32/Config_usb.h +++ /dev/null @@ -1,45 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef WIN32_H -#define WIN32_H -#include - -typedef struct Win32Handles -{ - HINSTANCE hInst; - HWND hWnd; - Win32Handles(HINSTANCE i, HWND w) - : hInst(i) - , hWnd(w) - { - } -} Win32Handles; - -#define CHECKED_SET_MAX_INT(var, hDlg, nIDDlgItem, bSigned, min, max) \ - do \ - { \ - /*CheckControlTextIsNumber(GetDlgItem(hDlg, nIDDlgItem), bSigned, 0);*/ \ - var = GetDlgItemInt(hDlg, nIDDlgItem, NULL, bSigned); \ - if (var < min) \ - var = min; \ - else if (var > max) \ - { \ - var = max; \ - SetDlgItemInt(hDlg, nIDDlgItem, var, bSigned); \ - SendMessage(GetDlgItem(hDlg, nIDDlgItem), EM_SETSEL, -2, -2); \ - } \ - } while (0) -#endif diff --git a/pcsx2/USB/Win32/USBDialog.rc b/pcsx2/USB/Win32/USBDialog.rc deleted file mode 100644 index 46ae18a270..0000000000 --- a/pcsx2/USB/Win32/USBDialog.rc +++ /dev/null @@ -1,206 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource_usb.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "WinResrc.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Anglais (États-Unis) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_DLGMSD_USB DIALOGEX 0, 0, 316, 74 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "USB Mass Storage Device" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,204,54,50,14 - PUSHBUTTON "Cancel",IDCANCEL,258,54,50,14 - GROUPBOX "Image file path",IDC_STATIC_USB,6,6,300,36 - EDITTEXT IDC_EDIT1_USB,12,18,234,14,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES - PUSHBUTTON "Browse",IDC_BUTTON1_USB,252,18,50,14 -END - -IDD_CONFIG_USB DIALOGEX 0, 0, 257, 205 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "USB Settings" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - PUSHBUTTON "Cancel",IDCANCEL,194,184,50,14 - DEFPUSHBUTTON "OK",IDOK,138,184,50,14 - GROUPBOX "Device type",IDC_STATIC_USB,6,6,246,48 - LTEXT "Port 1:",IDC_STATIC_USB,19,19,23,8 - COMBOBOX IDC_COMBO1_USB,48,17,198,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Port 2:",IDC_STATIC_USB,19,37,23,8 - COMBOBOX IDC_COMBO2_USB,48,35,198,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Device API",IDC_STATIC_USB,6,54,246,48 - LTEXT "Port 1:",IDC_STATIC_USB,19,67,23,8 - COMBOBOX IDC_COMBO_API1_USB,48,65,144,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "Configure",IDC_CONFIGURE1_USB,198,65,49,14 - LTEXT "Port 2:",IDC_STATIC_USB,19,85,23,8 - COMBOBOX IDC_COMBO_API2_USB,48,83,144,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "Configure",IDC_CONFIGURE2_USB,198,83,49,14 - CONTROL "Enable Logging (for developer use only)",IDC_LOGGING_USB, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,105,144,12 - GROUPBOX "Emulated device",IDC_STATIC_USB,6,131,246,48 - LTEXT "Port 1:",IDC_STATIC_USB,19,144,23,8 - COMBOBOX IDC_COMBO_WHEEL_TYPE1_USB,48,142,198,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Port 2:",IDC_STATIC_USB,19,162,23,8 - COMBOBOX IDC_COMBO_WHEEL_TYPE2_USB,48,160,198,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP -END - -IDD_DLGWASAPI_USB DIALOGEX 0, 0, 287, 230 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "WASAPI Settings" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,174,210,50,14 - PUSHBUTTON "Cancel",IDCANCEL,228,210,50,14 - GROUPBOX "Audio Input",IDC_STATIC_USB,6,6,270,54 - LTEXT "Player 1:",IDC_STATIC_USB,12,18,30,8 - LTEXT "Player 2:",IDC_STATIC_USB,12,36,30,8 - COMBOBOX IDC_COMBO1_USB,48,18,216,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO2_USB,48,36,216,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "1 ms",IDC_STATIC_USB,18,138,16,8 - LTEXT "1000 ms",IDC_STATIC_USB,240,138,28,8 - GROUPBOX "Input Buffering",IDC_STATIC_USB,6,108,270,46 - CONTROL "",IDC_SLIDER1_USB,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,18,121,252,15 - EDITTEXT IDC_BUFFER1_USB,122,138,40,12,ES_AUTOHSCROLL | ES_NUMBER - GROUPBOX "Audio Output",IDC_STATIC_USB,6,66,270,36 - COMBOBOX IDC_COMBO3_USB,48,78,216,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "1 ms",IDC_STATIC_USB,18,186,16,8 - LTEXT "1000 ms",IDC_STATIC_USB,240,186,28,8 - GROUPBOX "Output Buffering",IDC_STATIC_USB,6,156,270,46 - CONTROL "",IDC_SLIDER2_USB,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,18,169,252,15 - EDITTEXT IDC_BUFFER2_USB,122,186,40,12,ES_AUTOHSCROLL | ES_NUMBER -END - -IDD_DLG_EYETOY_USB DIALOGEX 0, 0, 309, 49 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "EyeToy Settings" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Device:",IDC_STATIC_USB,7,8,27,8 - COMBOBOX IDC_COMBO1_USB,40,7,262,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "OK",IDOK,198,28,50,14 - PUSHBUTTON "Cancel",IDCANCEL,252,28,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_DLGMIC_USB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_CONFIG_USB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DLGWASAPI_USB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DLG_EYETOY_USB AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_DLGMSD_USB, DIALOG - BEGIN - END - - IDD_CONFIG_USB, DIALOG - BEGIN - END - - IDD_DLGWASAPI_USB, DIALOG - BEGIN - END - - IDD_DLG_EYETOY_USB, DIALOG - BEGIN - END -END -#endif // APSTUDIO_INVOKED - -#endif // Anglais (États-Unis) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Espagnol (Argentine) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) -LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource_usb.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""WinResrc.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Espagnol (Argentine) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/pcsx2/USB/Win32/guid.cpp b/pcsx2/USB/Win32/guid.cpp deleted file mode 100644 index 927722327e..0000000000 --- a/pcsx2/USB/Win32/guid.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include -#include -#include -#include diff --git a/pcsx2/USB/Win32/resource_usb.h b/pcsx2/USB/Win32/resource_usb.h deleted file mode 100644 index 5368e9d6ae..0000000000 --- a/pcsx2/USB/Win32/resource_usb.h +++ /dev/null @@ -1,41 +0,0 @@ -//{{NO_DEPENDENCIES}} -// fichier Include Microsoft Visual C++. -// Utilisé par USBDialog.rc -// -#define IDC_CONFIGURE1_USB 3 -#define IDC_CONFIGURE2_USB 4 -#define IDD_CONFDLG_USB 101 -#define IDD_CONFIG_USB 101 -#define IDD_DLGMSD_USB 106 -#define IDD_DLGWASAPI_USB 107 -#define IDD_DLG_EYETOY_USB 108 -#define IDC_LOGGING_USB 1007 -#define IDC_COMBO1_USB 1008 -#define IDC_COMBO2_USB 1009 -#define IDC_LIST1_USB 1010 -#define IDC_COMBO_API1_USB 1010 -#define IDC_COMBO3_USB 1010 -#define IDC_COMBO_FFB_USB 1011 -#define IDC_COMBO_API2_USB 1011 -#define IDC_BUTTON1_USB 1012 -#define IDC_DFP_PASS_USB 1013 -#define IDC_EDIT1_USB 1015 -#define IDC_COMBO_WHEEL_TYPE1_USB 1037 -#define IDC_COMBO_WHEEL_TYPE2_USB 1038 -#define IDC_SLIDER1_USB 1039 -#define IDC_BUFFER1_USB 1040 -#define IDC_COMBOMICAPI_USB 1041 -#define IDC_SLIDER2_USB 1041 -#define IDC_BUFFER2_USB 1042 -#define IDC_STATIC_USB -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 109 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1042 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/pcsx2/USB/configuration.cpp b/pcsx2/USB/configuration.cpp deleted file mode 100644 index c40efe6230..0000000000 --- a/pcsx2/USB/configuration.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "deviceproxy.h" -#include "configuration.h" -#include "shared/inifile_usb.h" -#include "platcompat.h" -#include "Config.h" -#include "common/Path.h" -#include "common/StringUtil.h" -#include "gui/StringHelpers.h" -#include -#include - -std::map, std::string> changedAPIs; -std::map, int> changedSubtype; -wxString iniFileUSB(L"USB.ini"); -static TSTDSTRING usb_path; -TSTDSTRING IniPath; // default path, just in case -TSTDSTRING LogDir; -CIniFile ciniFile; -bool USBpathSet = false; - -void USBsetSettingsDir() -{ - if(!USBpathSet) - { - IniPath = StringUtil::UTF8StringToWxString(Path::Combine(EmuFolders::Settings, "USB.ini")); // default path, just in case - USBpathSet = true; - } -} - -void USBsetLogDir(const char* dir) -{ -#ifdef _WIN32 - LogDir = str_to_wstr(dir); -#else - LogDir = dir; -#endif -} - -std::string GetSelectedAPI(const std::pair& pair) -{ - USBsetSettingsDir(); - auto it = changedAPIs.find(pair); - if (it != changedAPIs.end()) - return it->second; - return std::string(); -} - -int GetSelectedSubtype(const std::pair& pair) -{ - auto it = changedSubtype.find(pair); - if (it != changedSubtype.end()) - return it->second; - return 0; -} - -bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, TSTDSTRING& value) -{ - USBsetSettingsDir(); - CIniKey* key; -#ifdef _WIN32 - auto sect = ciniFile.GetSection(section); - if (sect && (key = sect->GetKey(param))) - { - value = key->GetValue(); - return true; - } -#else - auto sect = ciniFile.GetSection(str_to_wstr(section)); - if (sect && (key = sect->GetKey(str_to_wstr(param)))) - { - value = wstr_to_str(key->GetValue()); - return true; - } -#endif - return false; -} - -bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, int32_t& value) -{ - USBsetSettingsDir(); - CIniKey* key; -#ifdef _WIN32 - auto sect = ciniFile.GetSection(section); - if (sect && (key = sect->GetKey(param))) - { - try - { - value = std::stoi(key->GetValue()); - return true; - } -#else - auto sect = ciniFile.GetSection(str_to_wstr(section)); - if (sect && (key = sect->GetKey(str_to_wstr(param)))) - { - try - { - value = std::stoi(key->GetValue()); - return true; - } -#endif - catch (std::exception& err) - { - DevCon.WriteLn("%s\n", err.what()); - } - } - return false; -} - -bool SaveSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, const TSTDSTRING& value) -{ - USBsetSettingsDir(); -#ifdef _WIN32 - ciniFile.SetKeyValue(section, param, value); -#else - ciniFile.SetKeyValue(str_to_wstr(section), str_to_wstr(param), str_to_wstr(value)); -#endif - return true; -} - -bool SaveSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, int32_t value) -{ - USBsetSettingsDir(); -#ifdef _WIN32 - ciniFile.SetKeyValue(section, param, TSTDTOSTRING(value)); -#else - ciniFile.SetKeyValue(str_to_wstr(section), str_to_wstr(param), str_to_wstr(TSTDTOSTRING(value))); -#endif - return true; -} - -void SaveConfig() -{ - USBsetSettingsDir(); -#ifdef _WIN32 - SaveSetting(L"MAIN", L"log", conf.Log); -#else - SaveSetting("MAIN", "log", conf.Log); -#endif - -#ifdef _WIN32 - SaveSetting(nullptr, 0, N_DEVICE_PORT, N_DEVICE, str_to_wstr(conf.Port[0])); - SaveSetting(nullptr, 1, N_DEVICE_PORT, N_DEVICE, str_to_wstr(conf.Port[1])); -#else - SaveSetting(nullptr, 0, N_DEVICE_PORT, N_DEVICE, conf.Port[0]); - SaveSetting(nullptr, 1, N_DEVICE_PORT, N_DEVICE, conf.Port[1]); -#endif - - for (auto& k : changedAPIs) - { -#ifdef _WIN32 - SaveSetting(nullptr, k.first.first, k.first.second, N_DEVICE_API, str_to_wstr(k.second)); -#else - SaveSetting(nullptr, k.first.first, k.first.second, N_DEVICE_API, k.second); -#endif - } - - for (auto& k : changedSubtype) - { - SaveSetting(nullptr, k.first.first, k.first.second, N_DEV_SUBTYPE, k.second); - } - -#ifdef _WIN32 - bool ret = ciniFile.Save(IniPath); -#else - [[maybe_unused]]bool ret = ciniFile.Save(str_to_wstr(IniPath)); -#endif -} - -void LoadConfig() -{ - USBsetSettingsDir(); - - static bool loaded = false; - if (loaded) - return; - loaded = true; - -#ifdef _WIN32 - ciniFile.Load(IniPath); - LoadSetting(L"MAIN", L"log", conf.Log); -#else - ciniFile.Load(str_to_wstr(IniPath)); - LoadSetting("MAIN", "log", conf.Log); -#endif - -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, 0, N_DEVICE_PORT, N_DEVICE, tmp); - conf.Port[0] = wstr_to_str(tmp); - LoadSetting(nullptr, 1, N_DEVICE_PORT, N_DEVICE, tmp); - conf.Port[1] = wstr_to_str(tmp); -#else - LoadSetting(nullptr, 0, N_DEVICE_PORT, N_DEVICE, conf.Port[0]); - LoadSetting(nullptr, 1, N_DEVICE_PORT, N_DEVICE, conf.Port[1]); -#endif - - auto& instance = RegisterDevice::instance(); - - for (int i = 0; i < 2; i++) - { - std::string api; -#ifdef _WIN32 - LoadSetting(nullptr, i, conf.Port[i], N_DEVICE_API, tmp); - api = wstr_to_str(tmp); -#else - LoadSetting(nullptr, i, conf.Port[i], N_DEVICE_API, api); -#endif - auto dev = instance.Device(conf.Port[i]); - - if (dev) - { - if (!dev->IsValidAPI(api)) - { - api = ""; - const auto& apis = dev->ListAPIs(); - if (!apis.empty()) - api = *apis.begin(); - - } - } - - if (api.size()) - changedAPIs[std::make_pair(i, conf.Port[i])] = api; - - int subtype = 0; - LoadSetting(nullptr, i, conf.Port[i], N_DEV_SUBTYPE, subtype); - changedSubtype[std::make_pair(i, conf.Port[i])] = subtype; - } -} - -void ClearSection(const TCHAR* section) -{ - USBsetSettingsDir(); -#ifdef _WIN32 - auto s = ciniFile.GetSection(section); -#else - auto s = ciniFile.GetSection(str_to_wstr(section)); -#endif - if (s) - { - s->RemoveAllKeys(); - } -} - -void RemoveSection(const char* dev_type, int port, const std::string& key) -{ - USBsetSettingsDir(); - TSTDSTRING tkey; - tkey.assign(key.begin(), key.end()); - - TSTDSTRINGSTREAM section; - if (dev_type) - section << dev_type << TEXT(" "); - section << tkey << TEXT(" ") << port; - TSTDSTRING str = section.str(); - -#ifdef _WIN32 - ciniFile.RemoveSection(section.str()); -#else - ciniFile.RemoveSection(str_to_wstr(section.str())); -#endif -} diff --git a/pcsx2/USB/configuration.h b/pcsx2/USB/configuration.h deleted file mode 100644 index 4d51038832..0000000000 --- a/pcsx2/USB/configuration.h +++ /dev/null @@ -1,162 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "platcompat.h" -#include -#include -#include -#include -#include - -#define RESULT_CANCELED 0 -#define RESULT_OK 1 -#define RESULT_FAILED 2 - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -// Device-level config related defines -#define S_DEVICE_API TEXT("Device API") -#define S_WHEEL_TYPE TEXT("Wheel type") -#define S_CONFIG_PATH TEXT("Path") - -#define N_DEVICE_API TEXT("device_api") -#define N_DEVICES TEXT("devices") -#define N_DEVICE TEXT("device") -#define N_WHEEL_PT TEXT("wheel_pt") -#define N_DEVICE_PORT0 TEXT("port_0") -#define N_DEVICE_PORT1 TEXT("port_1") -#define N_DEVICE_PORT "port" -#define N_DEV_SUBTYPE TEXT("subtype") -#define N_CONFIG_PATH TEXT("path") - -#define PLAYER_TWO_PORT 0 -#define PLAYER_ONE_PORT 1 -#define USB_PORT PLAYER_ONE_PORT - -struct Config -{ - int Log; - std::string Port[2]; - - Config(); -}; - -extern Config conf; -void SaveConfig(); -void LoadConfig(); -void ClearSection(const TCHAR* section); -void RemoveSection(const char* dev_type, int port, const std::string& key); - -extern TSTDSTRING IniPath; -extern TSTDSTRING LogDir; -extern std::map, std::string> changedAPIs; -extern std::map, int> changedSubtype; -std::string GetSelectedAPI(const std::pair& pair); -int GetSelectedSubtype(const std::pair& pair); - -bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, TSTDSTRING& value); -bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, int32_t& value); - -bool SaveSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, const TSTDSTRING& value); -bool SaveSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, int32_t value); - -#ifdef _UNICODE -bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, std::string& value); -bool SaveSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TCHAR* param, const std::string& value); -#endif - -void USBsetSettingsDir(); -void USBsetLogDir(const char* dir); - -template -bool LoadSetting(const char* dev_type, int port, const std::string& key, const TCHAR* name, Type& var) -{ - bool ret = false; - if (key.empty()) - { - return false; - } - - TSTDSTRING tkey; - tkey.assign(key.begin(), key.end()); - - TSTDSTRINGSTREAM section; - if (dev_type) - section << dev_type << TEXT(" "); - section << tkey << TEXT(" ") << port; - TSTDSTRING str = section.str(); - - ret = LoadSettingValue(IniPath, str, name, var); - return ret; -} - -template -bool LoadSetting(const TCHAR* section, const TCHAR* key, Type& var) -{ - bool ret = false; - ret = LoadSettingValue(IniPath, section, key, var); - return ret; -} - -/** - * - * [devices] - * portX = pad - * - * [pad X] - * api = joydev - * - * [joydev X] - * button0 = 1 - * button1 = 2 - * ... - * - * */ -template -bool SaveSetting(const char* dev_type, int port, const std::string& key, const TCHAR* name, const Type var) -{ - bool ret = false; - if (key.empty()) - { - return false; - } - - TSTDSTRING tkey; - tkey.assign(key.begin(), key.end()); - - TSTDSTRINGSTREAM section; - if (dev_type) - section << dev_type << TEXT(" "); - section << tkey << TEXT(" ") << port; - TSTDSTRING str = section.str(); - - - ret = SaveSettingValue(IniPath, str, name, var); - return ret; -} - -template -bool SaveSetting(const TCHAR* section, const TCHAR* key, const Type var) -{ - bool ret = false; - - ret = SaveSettingValue(IniPath, section, key, var); - return ret; -} diff --git a/pcsx2/USB/device_init.cpp b/pcsx2/USB/device_init.cpp deleted file mode 100644 index 7cbf26637b..0000000000 --- a/pcsx2/USB/device_init.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "deviceproxy.h" -#include "usb-eyetoy/usb-eyetoy-webcam.h" -#include "usb-hid/usb-hid.h" -#include "usb-mic/usb-headset.h" -#include "usb-mic/usb-mic-singstar.h" -#include "usb-msd/usb-msd.h" -#include "usb-pad/usb-pad.h" -#include "usb-printer/usb-printer.h" - -void RegisterDevice::Register() -{ - auto& inst = RegisterDevice::instance(); - if (inst.Map().size()) // FIXME Don't clear proxies, singstar keeps a copy to uninit audio - return; - inst.Add(DEVTYPE_PAD, new DeviceProxy()); - inst.Add(DEVTYPE_MSD, new DeviceProxy()); - inst.Add(DEVTYPE_SINGSTAR, new DeviceProxy()); - inst.Add(DEVTYPE_LOGITECH_MIC, new DeviceProxy()); - inst.Add(DEVTYPE_LOGITECH_HEADSET, new DeviceProxy()); - inst.Add(DEVTYPE_HIDKBD, new DeviceProxy()); - inst.Add(DEVTYPE_HIDMOUSE, new DeviceProxy()); - inst.Add(DEVTYPE_RBKIT, new DeviceProxy()); - inst.Add(DEVTYPE_BUZZ, new DeviceProxy()); -#ifdef _WIN32 - inst.Add(DEVTYPE_GAMETRAK, new DeviceProxy()); - inst.Add(DEVTYPE_REALPLAY, new DeviceProxy()); -#endif - inst.Add(DEVTYPE_EYETOY, new DeviceProxy()); - inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy()); - inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy()); - inst.Add(DEVTYPE_PRINTER, new DeviceProxy()); - inst.Add(DEVTYPE_KEYBOARDMANIA, new DeviceProxy()); - - RegisterAPIs(); -} - -void RegisterDevice::Unregister() -{ - /*for (auto& i: registerDeviceMap) - delete i.second;*/ - registerDeviceMap.clear(); - delete registerDevice; - registerDevice = nullptr; - - UnregisterAPIs(); -} diff --git a/pcsx2/USB/deviceproxy.cpp b/pcsx2/USB/deviceproxy.cpp index 42dd85f802..6c59733aec 100644 --- a/pcsx2/USB/deviceproxy.cpp +++ b/pcsx2/USB/deviceproxy.cpp @@ -15,25 +15,85 @@ #include "PrecompiledHeader.h" #include "deviceproxy.h" -#include "usb-pad/padproxy.h" -#include "usb-mic/audiodeviceproxy.h" -#include "usb-hid/hidproxy.h" -#include "usb-eyetoy/videodeviceproxy.h" +#include "usb-eyetoy/usb-eyetoy-webcam.h" +#include "usb-hid/usb-hid.h" +#include "usb-mic/usb-headset.h" +#include "usb-mic/usb-mic-singstar.h" +#include "usb-msd/usb-msd.h" +#include "usb-pad/usb-pad.h" +#include "usb-printer/usb-printer.h" +#include "usb-lightgun/guncon2.h" RegisterDevice* RegisterDevice::registerDevice = nullptr; -void RegisterAPIs() +DeviceProxy::~DeviceProxy() = default; + +std::vector DeviceProxy::SubTypes() const { - usb_pad::RegisterPad::Register(); - usb_mic::RegisterAudioDevice::Register(); - usb_hid::RegisterUsbHID::Register(); - usb_eyetoy::RegisterVideoDevice::Register(); + return {}; } -void UnregisterAPIs() +gsl::span DeviceProxy::Bindings(u32 subtype) const { - usb_pad::RegisterPad::instance().Clear(); - usb_mic::RegisterAudioDevice::instance().Clear(); - usb_hid::RegisterUsbHID::instance().Clear(); - usb_eyetoy::RegisterVideoDevice::instance().Clear(); + return {}; +} + +gsl::span DeviceProxy::Settings(u32 subtype) const +{ + return {}; +} + +float DeviceProxy::GetBindingValue(const USBDevice* dev, u32 bind) const +{ + return 0.0f; +} + +void DeviceProxy::SetBindingValue(USBDevice* dev, u32 bind, float value) const +{ +} + +bool DeviceProxy::Freeze(USBDevice* dev, StateWrapper& sw) const +{ + return false; +} + +void DeviceProxy::UpdateSettings(USBDevice* dev, SettingsInterface& si) const +{ +} + +void DeviceProxy::InputDeviceConnected(USBDevice* dev, const std::string_view& identifier) const +{ +} + +void DeviceProxy::InputDeviceDisconnected(USBDevice* dev, const std::string_view& identifier) const +{ +} + +void RegisterDevice::Register() +{ + auto& inst = RegisterDevice::instance(); + if (inst.Map().size()) // FIXME Don't clear proxies, singstar keeps a copy to uninit audio + return; + inst.Add(DEVTYPE_PAD, new usb_pad::PadDevice()); + inst.Add(DEVTYPE_MSD, new usb_msd::MsdDevice()); + inst.Add(DEVTYPE_SINGSTAR, new usb_mic::SingstarDevice()); + inst.Add(DEVTYPE_LOGITECH_MIC, new usb_mic::LogitechMicDevice()); + inst.Add(DEVTYPE_LOGITECH_HEADSET, new usb_mic::HeadsetDevice()); + inst.Add(DEVTYPE_HIDKBD, new usb_hid::HIDKbdDevice()); + inst.Add(DEVTYPE_HIDMOUSE, new usb_hid::HIDMouseDevice()); + inst.Add(DEVTYPE_RBKIT, new usb_pad::RBDrumKitDevice()); + inst.Add(DEVTYPE_BUZZ, new usb_pad::BuzzDevice()); + inst.Add(DEVTYPE_EYETOY, new usb_eyetoy::EyeToyWebCamDevice()); + inst.Add(DEVTYPE_BEATMANIA_DADADA, new usb_hid::BeatManiaDevice()); + inst.Add(DEVTYPE_SEGA_SEAMIC, new usb_pad::SeamicDevice()); + inst.Add(DEVTYPE_PRINTER, new usb_printer::PrinterDevice()); + inst.Add(DEVTYPE_KEYBOARDMANIA, new usb_pad::KeyboardmaniaDevice()); + inst.Add(DEVTYPE_GUNCON2, new usb_lightgun::GunCon2Device()); +} + +void RegisterDevice::Unregister() +{ + registerDeviceMap.clear(); + delete registerDevice; + registerDevice = nullptr; } diff --git a/pcsx2/USB/deviceproxy.h b/pcsx2/USB/deviceproxy.h index 35fd7ffd24..a3714cbb76 100644 --- a/pcsx2/USB/deviceproxy.h +++ b/pcsx2/USB/deviceproxy.h @@ -13,26 +13,27 @@ * If not, see . */ -#ifndef DEVICEPROXY_H -#define DEVICEPROXY_H -#include "configuration.h" +#pragma once + #include #include +#include #include #include #include #include -//#include -#include "helpers.h" -#include "proxybase.h" +#include +#include "gsl/span" + #include "qemu-usb/USBinternal.h" + +#include "Config.h" #include "SaveState.h" -void RegisterAPIs(); -void UnregisterAPIs(); +class StateWrapper; // also map key/array index -enum DeviceType +enum DeviceType : s32 { DEVTYPE_NONE = -1, DEVTYPE_PAD = 0, @@ -44,160 +45,35 @@ enum DeviceType DEVTYPE_HIDMOUSE, DEVTYPE_RBKIT, DEVTYPE_BUZZ, - DEVTYPE_GAMETRAK, - DEVTYPE_REALPLAY, DEVTYPE_EYETOY, DEVTYPE_BEATMANIA_DADADA, DEVTYPE_SEGA_SEAMIC, DEVTYPE_PRINTER, DEVTYPE_KEYBOARDMANIA, + DEVTYPE_GUNCON2 }; -struct SelectDeviceName -{ - template - std::string operator()(const std::pair& x) const - { - return x.second->TypeName(); - } -}; - -class DeviceError : public std::runtime_error +class DeviceProxy { public: - DeviceError(const char* msg) - : std::runtime_error(msg) - { - } - virtual ~DeviceError() {} -}; + virtual ~DeviceProxy(); -class DeviceProxyBase -{ -public: - DeviceProxyBase(){}; - virtual ~DeviceProxyBase() {} - virtual USBDevice* CreateDevice(int port) = 0; - virtual const TCHAR* Name() const = 0; + virtual const char* Name() const = 0; virtual const char* TypeName() const = 0; - virtual int Configure(int port, const std::string& api, void* data) = 0; - virtual std::list ListAPIs() = 0; - virtual const TCHAR* LongAPIName(const std::string& name) = 0; - virtual int Freeze(FreezeAction mode, USBDevice* dev, void* data) = 0; - virtual std::vector SubTypes() = 0; + virtual std::vector SubTypes() const; + virtual gsl::span Bindings(u32 subtype) const; + virtual gsl::span Settings(u32 subtype) const; - virtual bool IsValidAPI(const std::string& api) - { - const std::list& apis = ListAPIs(); - auto it = std::find(apis.begin(), apis.end(), api); - if (it != apis.end()) - return true; - return false; - } -}; + virtual USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const = 0; -template -class DeviceProxy : public DeviceProxyBase -{ -public: - DeviceProxy() {} - virtual ~DeviceProxy() - { - } - virtual USBDevice* CreateDevice(int port) - { - return T::CreateDevice(port); - } - virtual const TCHAR* Name() const - { - return T::Name(); - } - virtual const char* TypeName() const - { - return T::TypeName(); - } - virtual int Configure(int port, const std::string& api, void* data) - { - return T::Configure(port, api, data); - } - virtual std::list ListAPIs() - { - return T::ListAPIs(); - } - virtual const TCHAR* LongAPIName(const std::string& name) - { - return T::LongAPIName(name); - } - virtual int Freeze(FreezeAction mode, USBDevice* dev, void* data) - { - return T::Freeze(mode, dev, data); - } - virtual std::vector SubTypes() - { - return T::SubTypes(); - } -}; + virtual float GetBindingValue(const USBDevice* dev, u32 bind) const; + virtual void SetBindingValue(USBDevice* dev, u32 bind, float value) const; -template -class RegisterProxy -{ - RegisterProxy(const RegisterProxy&) = delete; - RegisterProxy() {} + virtual bool Freeze(USBDevice* dev, StateWrapper& sw) const; + virtual void UpdateSettings(USBDevice* dev, SettingsInterface& si) const; -public: - typedef std::map> RegisterProxyMap; - static RegisterProxy& instance() - { - static RegisterProxy registerProxy; - return registerProxy; - } - - virtual ~RegisterProxy() - { - Clear(); - } - - void Clear() - { - registerProxyMap.clear(); - } - - void Add(const std::string& name, T* creator) - { - registerProxyMap[name] = std::unique_ptr(creator); - } - - T* Proxy(const std::string& name) - { - return registerProxyMap[name].get(); - } - - std::list Names() const - { - std::list nameList; - std::transform( - registerProxyMap.begin(), registerProxyMap.end(), - std::back_inserter(nameList), - SelectKey()); - return nameList; - } - - std::string Name(int idx) const - { - auto it = registerProxyMap.begin(); - std::advance(it, idx); - if (it != registerProxyMap.end()) - return std::string(it->first); - return std::string(); - } - - const RegisterProxyMap& Map() const - { - return registerProxyMap; - } - -private: - RegisterProxyMap registerProxyMap; + virtual void InputDeviceConnected(USBDevice* dev, const std::string_view& identifier) const; + virtual void InputDeviceDisconnected(USBDevice* dev, const std::string_view& identifier) const; }; class RegisterDevice @@ -207,7 +83,7 @@ class RegisterDevice static RegisterDevice* registerDevice; public: - typedef std::map> RegisterDeviceMap; + typedef std::map> RegisterDeviceMap; static RegisterDevice& instance() { if (!registerDevice) @@ -220,18 +96,13 @@ public: static void Register(); void Unregister(); - void Add(DeviceType key, DeviceProxyBase* creator) + void Add(DeviceType key, DeviceProxy* creator) { - registerDeviceMap[key] = std::unique_ptr(creator); + registerDeviceMap[key] = std::unique_ptr(creator); } - DeviceProxyBase* Device(const std::string& name) + DeviceProxy* Device(const std::string_view& name) { - //return registerDeviceMap[name]; - /*for (auto& k : registerDeviceMap) - if(k.first.name == name) - return k.second; - return nullptr;*/ auto proxy = std::find_if(registerDeviceMap.begin(), registerDeviceMap.end(), [&name](const RegisterDeviceMap::value_type& val) -> bool { @@ -242,7 +113,7 @@ public: return nullptr; } - DeviceProxyBase* Device(int index) + DeviceProxy* Device(int index) { auto it = registerDeviceMap.begin(); std::advance(it, index); @@ -251,7 +122,7 @@ public: return nullptr; } - DeviceType Index(const std::string& name) + DeviceType Index(const std::string_view& name) { auto proxy = std::find_if(registerDeviceMap.begin(), registerDeviceMap.end(), @@ -263,25 +134,6 @@ public: return DEVTYPE_NONE; } - std::list Names() const - { - std::list nameList; - std::transform( - registerDeviceMap.begin(), registerDeviceMap.end(), - std::back_inserter(nameList), - SelectDeviceName()); - return nameList; - } - - std::string Name(int index) const - { - auto it = registerDeviceMap.begin(); - std::advance(it, index); - if (it != registerDeviceMap.end()) - return it->second->TypeName(); - return std::string(); - } - const RegisterDeviceMap& Map() const { return registerDeviceMap; @@ -290,5 +142,3 @@ public: private: RegisterDeviceMap registerDeviceMap; }; - -#endif diff --git a/pcsx2/USB/gtk.h b/pcsx2/USB/gtk.h deleted file mode 100644 index c8748b83e4..0000000000 --- a/pcsx2/USB/gtk.h +++ /dev/null @@ -1,19 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ -#pragma once - -#include - -GtkWidget* new_combobox(const char* label, GtkWidget* vbox, bool scrollable = false); // linux/config-gtk.cpp diff --git a/pcsx2/USB/helpers.h b/pcsx2/USB/helpers.h deleted file mode 100644 index a641f22aa8..0000000000 --- a/pcsx2/USB/helpers.h +++ /dev/null @@ -1,28 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef HELPERS_H -#define HELPERS_H - -struct SelectKey -{ - template - F operator()(const std::pair& x) const - { - return x.first; - } -}; - -#endif diff --git a/pcsx2/USB/icon_buzz_24.cpp b/pcsx2/USB/icon_buzz_24.cpp deleted file mode 100644 index d173263ae7..0000000000 --- a/pcsx2/USB/icon_buzz_24.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -// clang-format off -#include "icon_buzz_24.h" -const unsigned char icon_buzz_24[] -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa6, 0xf5, - 0xfd, 0xff, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfd, - 0xfd, 0xff, 0xfd, 0xf6, 0xa6, 0x39, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd6, 0x50, 0x00, 0x00, 0x00, 0x1e, 0xce, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xce, 0x1e, 0x00, 0x00, 0x8b, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8b, 0x00, - 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x5e, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x5e, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x5e, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, - 0x00, 0x8b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x8b, 0x00, 0x00, 0x1e, 0xce, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xce, 0x1e, 0x00, 0x00, 0x00, 0x50, 0xd6, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd6, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x39, 0xa6, 0xf0, 0xfd, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfd, - 0xf0, 0xa6, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -// clang-format on diff --git a/pcsx2/USB/icon_buzz_24.h b/pcsx2/USB/icon_buzz_24.h deleted file mode 100644 index 12ba435f67..0000000000 --- a/pcsx2/USB/icon_buzz_24.h +++ /dev/null @@ -1,17 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -extern const unsigned char icon_buzz_24[]; diff --git a/pcsx2/USB/linux/actualfile.c b/pcsx2/USB/linux/actualfile.c deleted file mode 100644 index 17b0fe7a78..0000000000 --- a/pcsx2/USB/linux/actualfile.c +++ /dev/null @@ -1,152 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include // errno -#include // open() -#include // rename() -#include // strerror() -#include // stat64(), open(), fstat() -#include // stat64(), open(), fstat(), lseek64() -#include // stat64(), fstat(), lseek64(), read(), close(), write() -// unlink() - -//#include "logfile.h" -#include "actualfile.h" -int IsActualFile(const char *filename) { - int retval; - struct stat64 filestat; - - errno = 0; - retval = stat64(filename, &filestat); - if((retval < 0) || (errno != 0)) { - return(-1); // Name doesn't exist. - } // ENDIF- Trouble getting stat on a file? - - if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. - return(0); // Yep, that's a file. -} // END IsActualFile() - - -void ActualFileDelete(const char *filename) { - - unlink(filename); -} // END ActualFileDelete() - - -void ActualFileRename(const char *origname, const char *newname) { - - rename(origname, newname); - return; -} // END ActualFileRename() - - -ACTUALHANDLE ActualFileOpenForRead(const char *filename) { - int newhandle; - - if(filename == NULL) return(-1); - - errno = 0; - newhandle = open(filename, O_RDONLY | O_LARGEFILE); - if((newhandle < 0) || (errno != 0)) { - return(-1); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForRead() - - -off64_t ActualFileSize(ACTUALHANDLE handle) { - int retval; - struct stat64 filestat; - - errno = 0; - retval = fstat64(handle, &filestat); - if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. - return(filestat.st_size); -} // END ActualFileSize() - - -int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { - off64_t moved; - - if(handle < 0) return(-1); - if(position < 0) return(-1); // Maybe... position = 0? - - errno = 0; - moved = lseek64(handle, position, SEEK_SET); - if(errno != 0) { - return(-1); - } // ENDIF- Error? Abort - - return(0); -} // END ActualFileSeek() - - -int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - - if(handle == ACTUALHANDLENULL) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - - errno = 0; - retval = read(handle, buffer, bytes); - if((retval < 0) || (errno != 0)) { - // return(-1); - } // ENDIF- Error? Abort - - return(retval); // Send back how many bytes read -} // END ActualFileRead() - - -void ActualFileClose(ACTUALHANDLE handle) { - if(handle < 0) return; - - errno = 0; - close(handle); - return; -} // END ActualFileClose() - - -ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { - int newhandle; - - if(filename == NULL) return(-1); - - errno = 0; - newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); - if((newhandle < 0) || (errno != 0)) { - return(-1); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForWrite() - - -int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - - if(handle < 0) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - - errno = 0; - retval = write(handle, buffer, bytes); - if((retval < 0) || (errno != 0)) { - // return(-1); - } // ENDIF- Error? Abort - - return(retval); // Send back how many bytes written -} // END ActualFileWrite() diff --git a/pcsx2/USB/linux/actualfile.h b/pcsx2/USB/linux/actualfile.h deleted file mode 100644 index ae7b1ffc84..0000000000 --- a/pcsx2/USB/linux/actualfile.h +++ /dev/null @@ -1,42 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef ACTUALFILE_H -#define ACTUALFILE_H - -#include // off64_t - - -#define ACTUALHANDLE int -#define ACTUALHANDLENULL -1 - -// #define VERBOSE_FUNCTION_ACTUALFILE -// #define VERBOSE_WARNING_ACTUALFILE - -extern int IsActualFile(const char* filename); -extern void ActualFileDelete(const char* filename); -extern void ActualFileRename(const char* origname, const char* newname); - -extern ACTUALHANDLE ActualFileOpenForRead(const char* filename); -extern off64_t ActualFileSize(ACTUALHANDLE handle); -extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); -extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char* buffer); -extern void ActualFileClose(ACTUALHANDLE handle); - -extern ACTUALHANDLE ActualFileOpenForWrite(const char* filename); -extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char* buffer); - - -#endif /* ACTUALFILE_H */ diff --git a/pcsx2/USB/linux/config-gtk.cpp b/pcsx2/USB/linux/config-gtk.cpp deleted file mode 100644 index 29c32e2d31..0000000000 --- a/pcsx2/USB/linux/config-gtk.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include "gui/AppCoreThread.h" -#include "USB/gtk.h" - -#include "USB/configuration.h" -#include "USB/deviceproxy.h" -#include "USB/usb-pad/padproxy.h" -#include "USB/usb-mic/audiodeviceproxy.h" - -#include "config.h" -#include "USB/USB.h" - -struct SettingsCB -{ - int player; - std::string device; - std::string api; - GtkComboBox* combo; - GtkComboBox* subtype; -}; - -gboolean run_msg_dialog(gpointer data) -{ - GtkWidget* dialog = (GtkWidget*)data; - gtk_widget_show_all(dialog); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - return FALSE; -} - -static void populateApiWidget(SettingsCB* settingsCB, const std::string& device) -{ - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(settingsCB->combo))); - - auto dev = RegisterDevice::instance().Device(device); - GtkComboBox* widget = settingsCB->combo; - if (dev) - { - int port = 1 - settingsCB->player; - - std::string api; - - auto it = changedAPIs.find(std::make_pair(port, device)); - if (it == changedAPIs.end()) - { - LoadSetting(nullptr, port, device, N_DEVICE_API, api); - if (!dev->IsValidAPI(api)) - api.clear(); - } - else - api = it->second; - - settingsCB->api = api; - int i = 0; - for (auto& it : dev->ListAPIs()) - { - auto name = dev->LongAPIName(it); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), name); - if (api.size() && api == it) - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), i); - else - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); - i++; - } - } -} - -static void populateSubtypeWidget(SettingsCB* settingsCB, const std::string& device) -{ - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(settingsCB->subtype))); - - auto dev = RegisterDevice::instance().Device(device); - GtkComboBox* widget = settingsCB->subtype; - if (dev) - { - int port = 1 - settingsCB->player; - int sel = 0; - if (!LoadSetting(nullptr, port, device, N_DEV_SUBTYPE, sel)) - { - changedSubtype[std::make_pair(port, device)] = sel; - } - - for (auto subtype : dev->SubTypes()) - { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), subtype.c_str()); - } - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), sel); - } -} - -static void deviceChanged(GtkComboBox* widget, gpointer data) -{ - SettingsCB* settingsCB = (SettingsCB*)data; - gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - int player = settingsCB->player; - std::string s; - - if (active > 0) - s = RegisterDevice::instance().Name(active - 1); - - settingsCB->device = s; - populateApiWidget(settingsCB, s); - populateSubtypeWidget(settingsCB, s); - - if (player == 0) - conf.Port[1] = s; - else - conf.Port[0] = s; - -} - -static void apiChanged(GtkComboBox* widget, gpointer data) -{ - SettingsCB* settingsCB = (SettingsCB*)data; - int player = settingsCB->player; - gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - - auto& name = settingsCB->device; - auto dev = RegisterDevice::instance().Device(name); - if (dev) - { - auto apis = dev->ListAPIs(); - auto it = apis.begin(); - std::advance(it, active); - if (it != apis.end()) - { - int port = 1 - player; - auto pair = std::make_pair(port, name); - auto itAPI = changedAPIs.find(pair); - - if (itAPI != changedAPIs.end()) - itAPI->second = *it; - else - changedAPIs[pair] = *it; - settingsCB->api = *it; - } - } -} - -static void subtypeChanged(GtkComboBox* widget, gpointer data) -{ - SettingsCB* settingsCB = (SettingsCB*)data; - int player = settingsCB->player; - gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - - auto& name = settingsCB->device; - auto dev = RegisterDevice::instance().Device(name); - if (dev) - { - int port = 1 - player; - changedSubtype[std::make_pair(port, name)] = active; - } -} - -static void configureApi(GtkWidget* widget, gpointer data) -{ - SettingsCB* settingsCB = (SettingsCB*)data; - int player = settingsCB->player; - - auto& name = settingsCB->device; - auto dev = RegisterDevice::instance().Device(name); - - if (dev) - { - int port = 1 - player; - auto& api = settingsCB->api; - - GtkWidget* dlg = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "dlg")); - [[maybe_unused]]int res = dev->Configure(port, api, dlg); - } -} - -GtkWidget* new_combobox(const char* label, GtkWidget* vbox, bool scrollable) -{ - GtkWidget *rs_hbox, *rs_label, *rs_cb; - - rs_hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), rs_hbox, FALSE, TRUE, 0); - - rs_label = gtk_label_new(label); - gtk_box_pack_start(GTK_BOX(rs_hbox), rs_label, FALSE, TRUE, 5); - gtk_label_set_justify(GTK_LABEL(rs_label), GTK_JUSTIFY_RIGHT); - - rs_cb = gtk_combo_box_text_new(); - if (!scrollable) - gtk_box_pack_start(GTK_BOX(rs_hbox), rs_cb, TRUE, TRUE, 5); - else - { - GtkWidget* sw = gtk_scrolled_window_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(sw), rs_cb); - gtk_box_pack_start(GTK_BOX(rs_hbox), sw, TRUE, TRUE, 5); - } - return rs_cb; -} - -static GtkWidget* new_frame(const char* label, GtkWidget* box) -{ - GtkWidget* ro_frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(box), ro_frame, TRUE, FALSE, 0); - - GtkWidget* ro_label = gtk_label_new(label); - gtk_frame_set_label_widget(GTK_FRAME(ro_frame), ro_label); - gtk_label_set_use_markup(GTK_LABEL(ro_label), TRUE); - - GtkWidget* vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ro_frame), vbox); - return vbox; -} - - -void USBconfigure() -{ - ScopedCoreThreadPause paused_core; - - USBsetSettingsDir(); - RegisterDevice::Register(); - LoadConfig(); - SettingsCB settingsCB[2]; - settingsCB[0].player = 0; - settingsCB[1].player = 1; - - const char* players[] = {"Player 1:", "Player 2:"}; - - GtkWidget *rs_cb, *vbox; - - // Create the dialog window - GtkWidget* dlg = gtk_dialog_new_with_buttons( - "USB Settings", NULL, GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE); - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - GtkWidget* main_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(dlg_area_box), main_vbox); - - /*** Device type ***/ - vbox = new_frame("Select device type:", main_vbox); - - std::string devs[2] = {conf.Port[1], conf.Port[0]}; - /*** Devices' Comboboxes ***/ - for (int ply = 0; ply < 2; ply++) - { - settingsCB[ply].device = devs[ply]; - - rs_cb = new_combobox(players[ply], vbox); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), "None"); - gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), 0); - - auto devices = RegisterDevice::instance().Names(); - int idx = 0; - for (auto& device : devices) - { - auto deviceProxy = RegisterDevice::instance().Device(device); - if (!deviceProxy) - { - continue; - } - auto name = deviceProxy->Name(); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), name); - idx++; - if (devs[ply] == device) - gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), idx); - } - g_signal_connect(G_OBJECT(rs_cb), "changed", G_CALLBACK(deviceChanged), (gpointer)&settingsCB[ply]); - } - - /*** APIs ***/ - vbox = new_frame("Select device API:", main_vbox); - - /*** API Comboboxes ***/ - for (int ply = 0; ply < 2; ply++) - { - rs_cb = new_combobox(players[ply], vbox); - settingsCB[ply].combo = GTK_COMBO_BOX(rs_cb); - //gtk_combo_box_set_active (GTK_COMBO_BOX (rs_cb), sel_idx); - g_signal_connect(G_OBJECT(rs_cb), "changed", G_CALLBACK(apiChanged), (gpointer)&settingsCB[ply]); - - GtkWidget* hbox = gtk_widget_get_parent(rs_cb); - GtkWidget* button = gtk_button_new_with_label("Configure"); - gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_icon_name("gtk-preferences", GTK_ICON_SIZE_BUTTON)); - gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5); - - g_signal_connect(button, "clicked", G_CALLBACK(configureApi), (gpointer)&settingsCB[ply]); - g_object_set_data(G_OBJECT(button), "dlg", dlg); - - populateApiWidget(&settingsCB[ply], devs[ply]); - } - - /** Emulated device / Wheel type **/ - vbox = new_frame("Emulated device:", main_vbox); - - for (int ply = 0; ply < 2; ply++) - { - rs_cb = new_combobox(players[ply], vbox); - settingsCB[ply].subtype = GTK_COMBO_BOX(rs_cb); - g_signal_connect(G_OBJECT(rs_cb), "changed", G_CALLBACK(subtypeChanged), (gpointer)&settingsCB[ply]); - - populateSubtypeWidget(&settingsCB[ply], devs[ply]); - } - - gtk_widget_show_all(dlg); - - // Modal loop - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - gtk_widget_destroy(dlg); - - // Wait for all gtk events to be consumed ... - while (gtk_events_pending()) - gtk_main_iteration_do(FALSE); - - if (result == GTK_RESPONSE_OK) - { - SaveConfig(); - CreateDevices(); - } - // ClearAPIs(); - paused_core.AllowResume(); -} - -void CALLBACK USBabout() -{ -} diff --git a/pcsx2/USB/linux/config.cpp b/pcsx2/USB/linux/config.cpp deleted file mode 100644 index 4ea1162639..0000000000 --- a/pcsx2/USB/linux/config.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "config.h" - -#include "USB/configuration.h" -#include "USB/deviceproxy.h" -#include "USB/usb-pad/padproxy.h" -#include "USB/usb-mic/audiodeviceproxy.h" -#include "common/Console.h" - -void SysMessage_stderr(const char* fmt, ...) -{ - va_list arglist; - - va_start(arglist, fmt); - Console.Warning(fmt, arglist); - va_end(arglist); -} diff --git a/pcsx2/USB/linux/config.h b/pcsx2/USB/linux/config.h deleted file mode 100644 index 6152ec76b1..0000000000 --- a/pcsx2/USB/linux/config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef LINUXCONFIG_H -#define LINUXCONFIG_H -#include -#include - -#endif diff --git a/pcsx2/USB/linux/ini.c b/pcsx2/USB/linux/ini.c deleted file mode 100644 index 85d146ddab..0000000000 --- a/pcsx2/USB/linux/ini.c +++ /dev/null @@ -1,594 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include // NULL -#include // sprintf() -#include // va_start(), va_end(), vsprintf() -//#include "logfile.h" -#include "actualfile.h" -#include "ini.h" - -//#define VERBOSE_FUNCTION_INI 1 -const char INIext[] = ".ini"; -const char INInewext[] = ".new"; - -// Returns: position where new extensions should be added. -int INIRemoveExt(const char *argname, char *tempname) { - int i; - int j; - int k; - - i = 0; - while((i <= INIMAXLEN) && (*(argname + i) != 0)) { - *(tempname + i) = *(argname + i); - i++; - } // ENDWHILE- Copying the argument name into a temporary area; - *(tempname + i) = 0; // And 0-terminate - k = i; - k--; - - j = 0; - while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; - j--; - - while((j >= 0) && (*(tempname + k) == INIext[j])) { - k--; - j--; - } // ENDWHILE- Comparing the ending characters to the INI ext. - if(j < 0) { - k++; - i = k; - *(tempname + i) = 0; // 0-terminate, cutting off ".ini" - } // ENDIF- Do we have a match? Then remove the end chars. - - return(i); -} // END INIRemoveExt() - - -void INIAddInExt(char *tempname, int temppos) { - int i; - - i = 0; - while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { - *(tempname + temppos + i) = INIext[i]; - i++; - } // ENDWHILE- Attaching extenstion to filename - *(tempname + temppos + i) = 0; // And 0-terminate -} // END INIAddInExt() - - -void INIAddOutExt(char *tempname, int temppos) { - int i; - - i = 0; - while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { - *(tempname + temppos + i) = INInewext[i]; - i++; - } // ENDWHILE- Attaching extenstion to filename - *(tempname + temppos + i) = 0; // And 0-terminate -} // END INIAddInExt() - - -// Returns number of bytes read to get line (0 means end-of-file) -int INIReadLine(ACTUALHANDLE infile, char *buffer) { - int charcount = 0; - int i = 0; - char tempin[2] = {0}; - int retflag = 0; - - while((i < INIMAXLEN) && (retflag < 2)) { - const int retval = ActualFileRead(infile, 1, tempin); - charcount++; - if(retval != 1) { - retflag = 2; - charcount--; - - } else if(tempin[0] == '\n') { - retflag = 2; - - } else if(tempin[0] >= ' ') { - *(buffer + i) = tempin[0]; - i++; - } // ENDLONGIF- How do we react to the next character? - } // ENDWHILE- Loading up on characters until an End-of-Line appears - *(buffer + i) = 0; // And 0-terminate - - return(charcount); -} // END INIReadLine() -// Note: Do we need to back-skip a char if something other \n follows \r? - - -// Returns: number of bytes to get to start of section (or -1) -int INIFindSection(ACTUALHANDLE infile, const char *section) { - int charcount = 0; - int retflag = 0; - char scanbuffer[INIMAXLEN+1]; - - while(retflag == 0) { - const int retval = INIReadLine(infile, scanbuffer); - if(retval == 0) return(-1); // EOF? Stop here. - - if(scanbuffer[0] == '[') { - int i = 0; - while((i < INIMAXLEN) && - (*(section + i) != 0) && - (*(section + i) == scanbuffer[i + 1])) i++; - if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { - if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { - retflag = 1; - } // ENDIF- End marks look good? Return successful. - } // ENDIF- Do we have a section match? - } // ENDIF- Does this look like a section header? - - if(retflag == 0) charcount += retval; - } // ENDWHILE- Scanning lines for the correct [Section] header. - - return(charcount); -} // END INIFindSection() - -// Returns: number of bytes to get to start of keyword (or -1) -int INIFindKeyword(ACTUALHANDLE infile, const char *keyword, char *buffer) { - int charcount = 0; - int retflag = 0; - char scanbuffer[INIMAXLEN+1]; - - while(retflag == 0) { - int retval = INIReadLine(infile, scanbuffer); - if(retval == 0) return(-1); // EOF? Stop here. - if(scanbuffer[0] == '[') return(-1); // New section? Stop here. - - int i = 0; - while((i < INIMAXLEN) && - (*(keyword + i) != 0) && - (*(keyword + i) == scanbuffer[i])) i++; - if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { - if(scanbuffer[i] == '=') { - retflag = 1; - if(buffer != NULL) { - i++; - int j = 0; - while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { - *(buffer + j) = scanbuffer[i]; - i++; - j++; - } // ENDWHILE- Copying the value out to the outbound buffer. - *(buffer + j) = 0; // And 0-terminate. - } // ENDIF- Return the value as well? - } // ENDIF- End marks look good? Return successful. - } // ENDIF- Do we have a section match? - - if(retflag == 0) charcount += retval; - } // ENDWHILE- Scanning lines for the correct [Section] header. - - return(charcount); -} // END INIFindKeyWord() - - -// Returns: number of bytes left to write... (from charcount back) -int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { - char buffer[4096]; - int chunk = 4096; - - int i = charcount; - chunk = 4096; - if(i < chunk) chunk = i; - while(chunk > 0) { - int retval = ActualFileRead(infile, chunk, buffer); - if(retval <= 0) return(i); // Trouble? Stop here. - if(retval < chunk) chunk = retval; // Short block? Note it. - - retval = ActualFileWrite(outfile, chunk, buffer); - if(retval <= 0) return(i); // Trouble? Stop here. - i -= retval; - if(retval < chunk) return(i); // Short block written? Stop here. - - chunk = 4096; - if(i < chunk) chunk = i; - } // ENDWHILE- Copying a section of file across, one chunk at a time. - - return(0); -} // END INICopyToPos() - - -int INISaveString(const char *file, const char *section, const char *keyword, const char *value) { - char inname[INIMAXLEN+1]; - char outname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - ACTUALHANDLE outfile; - int i; - int retval; - char templine[INIMAXLEN+1]; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - if(keyword == NULL) return(-1); - if(value == NULL) return(-1); - - filepos = INIRemoveExt(file, inname); - for(i = 0; i <= filepos; i++) outname[i] = inname[i]; - INIAddInExt(inname, filepos); - INIAddOutExt(outname, filepos); - - filepos = 0; - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) { - outfile = ActualFileOpenForWrite(inname); - if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. - - sprintf(templine, "[%s]\r\n", section); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - if(retval < i) { - ActualFileDelete(inname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - return(0); - } // ENDIF- No input file? Create a brand new .ini file then. - - retval = INIFindSection(infile, section); - if(retval < 0) { - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); // Move ini to beginning of file... - INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... - - sprintf(templine, "\r\n[%s]\r\n", section); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - if(retval < i) { - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); - } // ENDIF- Couldn't find the section? Make a new one! - - filepos = retval; - ActualFileSeek(infile, filepos); - filepos += INIReadLine(infile, templine); // Get section line's byte count - - retval = INIFindKeyword(infile, keyword, NULL); - if(retval < 0) { - ActualFileSeek(infile, filepos); - retval = INIReadLine(infile, templine); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; - while((retval > 0) && (templine[i] == '=')) { - filepos += retval; - retval = INIReadLine(infile, templine); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; - } // ENDWHILE- skimming to the bottom of the section - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - } else { - filepos += retval; // Position just before old version of keyword - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - INIReadLine(infile, templine); // Read past old keyword/value... - - // Replace with new value - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - } // ENDIF- Need to add a new keyword? - - INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); -} // END INISaveString() - - -int INILoadString(const char *file, const char *section, const char *keyword, char *buffer) { - char inname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - int retval; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - if(keyword == NULL) return(-1); - if(buffer == NULL) return(-1); - - filepos = INIRemoveExt(file, inname); - INIAddInExt(inname, filepos); - - filepos = 0; - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) return(-1); - - retval = INIFindSection(infile, section); - if(retval < 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Didn't find it? Abort. - - retval = INIFindKeyword(infile, keyword, buffer); - if(retval < 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Didn't find it? Abort. - - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(0); -} // END INILoadString() - - -int INIRemove(const char *file, const char *section, const char *keyword) { - char inname[INIMAXLEN+1]; - char outname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - ACTUALHANDLE outfile; - char templine[INIMAXLEN+1]; - int i; - int retval; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - - - filepos = INIRemoveExt(file, inname); - for(i = 0; i <= filepos; i++) outname[i] = inname[i]; - INIAddInExt(inname, filepos); - INIAddOutExt(outname, filepos); - - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) return(-1); - - retval = INIFindSection(infile, section); - if(retval == -1) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't even find the section? Abort - - filepos = retval; - if(keyword == NULL) { - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to the section? Abort. - - templine[0] = 0; - retval = 1; - while((retval > 0) && (templine[0] != '[')) { - retval = INIReadLine(infile, templine); - } // ENDWHILE- Read to the start of the next section... or EOF. - - if(templine[0] == '[') { - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - } // ENDIF- Are there other sections after this one? Save them then. - - } else { - filepos = retval; - ActualFileSeek(infile, filepos); - filepos += INIReadLine(infile, templine); // Get section line's byte count - - retval = INIFindKeyword(infile, keyword, NULL); - if(retval == -1) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't find the keyword? Abort - filepos += retval; - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - INIReadLine(infile, templine); // Read (and discard) the keyword line - } // ENDIF- Wipe out the whole section? Or just a keyword? - - INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); -} // END INIRemove() - - -int INISaveUInt(const char *file, const char *section, const char *keyword, unsigned int value) { - char numvalue[INIMAXLEN+1]; - - sprintf(numvalue, "%u", value); - return(INISaveString(file, section, keyword, numvalue)); -} // END INISaveUInt() - - -int INILoadUInt(const char *file, const char *section, const char *keyword, unsigned int *buffer) { - char numvalue[INIMAXLEN+1]; - int retval; - unsigned int value; - // unsigned int sign; // Not needed in unsigned numbers - int pos; - - if(buffer == NULL) return(-1); - *(buffer) = 0; - - retval = INILoadString(file, section, keyword, numvalue); - if(retval < 0) return(retval); - - value = 0; - // sign = 1; // Start positive - pos = 0; - - // Note: skip leading spaces? (Shouldn't have to, I hope) - - // if(numvalue[pos] == '-') { - // pos++; - // sign = -1; - // } // ENDIF- Negative sign check - - while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { - if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? - - if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { - value *= 10; - value += numvalue[pos] - '0'; - pos++; - } else { - numvalue[pos] = 0; - } // ENDIF- Add a digit in? Or stop searching for digits? - } // ENDWHILE- Adding digits of info to our ever-increasing value - - // value *= sign - *(buffer) = value; - return(0); -} // END INILoadUInt() diff --git a/pcsx2/USB/linux/ini.h b/pcsx2/USB/linux/ini.h deleted file mode 100644 index 184f6257c4..0000000000 --- a/pcsx2/USB/linux/ini.h +++ /dev/null @@ -1,61 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef INI_H -#define INI_H - - -// #ifndef __LINUX__ -// #ifdef __linux__ -// #define __LINUX__ -// #endif /* __linux__ */ -// #endif /* No __LINUX__ */ - -// #define CDVDdefs - - -// File format: -// [section] -// keyword=value - -// file - Name of the INI file -// section - Section within the file -// keyword - Identifier for a value -// value - value to store with a keyword in a section in the file -// buffer - place to retrieve the value of a keyword - -// return values: 0 = success, -1 = failure - - -// #define VERBOSE_FUNCTION_INI - -#define INIMAXLEN 255 - -#if __cplusplus -extern "C" { -#endif -extern int INISaveString(const char* file, const char* section, const char* keyword, const char* value); -extern int INILoadString(const char* file, const char* section, const char* keyword, char* buffer); - -extern int INISaveUInt(const char* file, const char* section, const char* keyword, unsigned int value); -extern int INILoadUInt(const char* file, const char* section, const char* keyword, unsigned int* buffer); - -// NULL in the keyword below removes the whole section. -extern int INIRemove(const char* file, const char* section, const char* keyword); - -#if __cplusplus -} -#endif -#endif /* INI_H */ diff --git a/pcsx2/USB/linux/util.cpp b/pcsx2/USB/linux/util.cpp deleted file mode 100644 index 990a5e6ec8..0000000000 --- a/pcsx2/USB/linux/util.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "util.h" -#include -#include -#include - -bool file_exists(std::string path) -{ - struct stat s; - return !stat(path.c_str(), &s) && !S_ISDIR(s.st_mode); -} - -bool dir_exists(std::string path) -{ - struct stat s; - return !stat(path.c_str(), &s) && S_ISDIR(s.st_mode); -} diff --git a/pcsx2/USB/platcompat.h b/pcsx2/USB/platcompat.h deleted file mode 100644 index ee7e7db9a1..0000000000 --- a/pcsx2/USB/platcompat.h +++ /dev/null @@ -1,132 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -// Annoying defines -// --------------------------------------------------------------------- -// make sure __POSIX__ is defined for all systems where we assume POSIX -// compliance -#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) || defined(__CYGWIN__) || defined(__LINUX__) -#if !defined(__POSIX__) -#define __POSIX__ 1 -#endif -#endif - -#ifndef EXPORT_C_ -#ifdef _MSC_VER -#define EXPORT_C_(type) extern "C" type CALLBACK -#elif defined(__i386__) -#define EXPORT_C_(type) extern "C" __attribute__((stdcall, visibility("default"))) type -#else -#define EXPORT_C_(type) extern "C" __attribute__((visibility("default"))) type -//#define EXPORT_C_(type) extern "C" __attribute__((stdcall,visibility("default"))) type -#endif -#endif - -#ifdef _WIN32 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#define wfopen _wfopen -#define fseeko64 _fseeki64 -#define ftello64 _ftelli64 -#define TSTDSTRING std::wstring -#define TSTDSTRINGSTREAM std::wstringstream -#define TSTDTOSTRING std::to_wstring - -//FIXME narrow string fmt -#define SFMTs "S" - -#define __builtin_constant_p(p) false - -void SysMessageW(const wchar_t* fmt, ...); -#define SysMessage SysMessageW - -#else //_WIN32 - -#define MAX_PATH PATH_MAX -#define __inline inline - -//#ifndef TEXT -//#define TEXT(x) L##x -//#endif -//FIXME narrow string fmt -#define SFMTs "s" -#define TEXT(val) val -#define TCHAR char -#define wfopen fopen -#define TSTDSTRING std::string -#define TSTDSTRINGSTREAM std::stringstream -#define TSTDTOSTRING std::to_string - -void SysMessage(const char* fmt, ...); - -#endif //_WIN32 - -#if __MINGW32__ - -#define DBL_EPSILON 2.2204460492503131e-16 -#define FLT_EPSILON 1.1920928955078125e-7f - -template -errno_t mbstowcs_s( - size_t* pReturnValue, - wchar_t (&wcstr)[size], - const char* mbstr, - size_t count) -{ - return mbstowcs_s(pReturnValue, wcstr, size, mbstr, count); -} - -template -errno_t wcstombs_s( - size_t* pReturnValue, - char (&mbstr)[size], - const wchar_t* wcstr, - size_t count) -{ - return wcstombs_s(pReturnValue, mbstr, size, wcstr, count); -} - -#endif //__MINGW32__ - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0]))) -#endif - -#include - -template -constexpr std::size_t countof(const T (&)[N]) noexcept -{ - return N; -} - -template -constexpr std::size_t countof(const T N) -{ - return N.size(); -} - -//TODO Idk, used only in desc.h and struct USBDescriptor should be already packed anyway -#if defined(_WIN32) && !defined(__MINGW32__) -#define PACK(def, name) __pragma(pack(push, 1)) def name __pragma(pack(pop)) -#elif defined(__clang__) -#define PACK(def, name) def __attribute__((packed)) name -#else -#define PACK(def, name) def __attribute__((gcc_struct, packed)) name -#endif diff --git a/pcsx2/USB/proxybase.h b/pcsx2/USB/proxybase.h deleted file mode 100644 index 7f01e5ce1e..0000000000 --- a/pcsx2/USB/proxybase.h +++ /dev/null @@ -1,25 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -//TODO Maybe too much inheritance? -class ProxyBase -{ -public: - ProxyBase() {} - virtual ~ProxyBase() {} - virtual const TCHAR* Name() const = 0; - virtual int Configure(int port, const char* dev_type, void* data) = 0; -}; diff --git a/pcsx2/USB/qemu-usb/USBinternal.h b/pcsx2/USB/qemu-usb/USBinternal.h index 2a8650c5c0..fac37ef702 100644 --- a/pcsx2/USB/qemu-usb/USBinternal.h +++ b/pcsx2/USB/qemu-usb/USBinternal.h @@ -13,10 +13,9 @@ * If not, see . */ -#ifndef USBINTERNAL_H -#define USBINTERNAL_H +#pragma once -#include "vl.h" +#include "USB/qemu-usb/qusb.h" /* Dump packet contents. */ //#define DEBUG_PACKET @@ -28,8 +27,8 @@ #define OHCI_MAX_PORTS 15 // status regs from 0x0c54 but usb snooping // reg is at 0x0c80, so only 11 ports? -extern int64_t usb_frame_time; -extern int64_t usb_bit_time; +extern int64_t g_usb_frame_time; +extern int64_t g_usb_bit_time; typedef struct OHCIPort { @@ -42,7 +41,6 @@ typedef uint32_t target_phys_addr_t; typedef struct OHCIState { target_phys_addr_t mem_base; - int mem; uint32_t num_ports; uint64_t eof_timer; @@ -106,7 +104,7 @@ struct ohci_hcca const typeof(((type *) 0)->member) *__mptr = (ptr); \ (type *) ((char *) __mptr - offsetof(type, member));}) */ -#define CONTAINER_OF(p, type, field) ((type*)((char*)p - ((ptrdiff_t) & ((type*)0)->field))) +#define USB_CONTAINER_OF(p, type, field) ((type*)((char*)p - ((ptrdiff_t) & ((type*)0)->field))) #define HCCA_WRITEBACK_OFFSET 128 //offsetof(struct ohci_hcca, frame) #define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */ @@ -306,4 +304,3 @@ void ohci_hard_reset(OHCIState* ohci); void ohci_soft_reset(OHCIState* ohci); int ohci_bus_start(OHCIState* ohci); void ohci_bus_stop(OHCIState* ohci); -#endif diff --git a/pcsx2/USB/qemu-usb/bus.cpp b/pcsx2/USB/qemu-usb/bus.cpp index 989b9e5534..036e6e80cd 100644 --- a/pcsx2/USB/qemu-usb/bus.cpp +++ b/pcsx2/USB/qemu-usb/bus.cpp @@ -14,8 +14,8 @@ */ #include "PrecompiledHeader.h" -#include "USBinternal.h" -#include "vl.h" +#include "USB/qemu-usb/USBinternal.h" +#include "USB/qemu-usb/qusb.h" #define USB_DEVICE_GET_CLASS(p) (&p->klass) diff --git a/pcsx2/USB/qemu-usb/core.cpp b/pcsx2/USB/qemu-usb/core.cpp index 416fac3766..45b1ae3e51 100644 --- a/pcsx2/USB/qemu-usb/core.cpp +++ b/pcsx2/USB/qemu-usb/core.cpp @@ -25,10 +25,9 @@ */ #include "PrecompiledHeader.h" -#include "USB/platcompat.h" -#include "vl.h" -#include "iov.h" -//#include "trace.h" +#include "USB/qemu-usb/qusb.h" +#include "USB/qemu-usb/iov.h" +#include void usb_pick_speed(USBPort* port) { @@ -39,9 +38,8 @@ void usb_pick_speed(USBPort* port) USB_SPEED_LOW, }; USBDevice* udev = port->dev; - int i; - for (i = 0; i < (int)ARRAY_SIZE(speeds); i++) + for (u32 i = 0; i < std::size(speeds); i++) { if ((udev->speedmask & (1 << speeds[i])) && (port->speedmask & (1 << speeds[i]))) @@ -568,7 +566,7 @@ void usb_cancel_packet(USBPacket* p) void usb_packet_init(USBPacket* p) { - qemu_iovec_init(&p->iov, 1); + qemu_iovec_init(&p->iov); } static const char* usb_packet_state_name(USBPacketState state) @@ -581,7 +579,7 @@ static const char* usb_packet_state_name(USBPacketState state) /*[USB_PACKET_COMPLETE] =*/"complete", /*[USB_PACKET_CANCELED] =*/"canceled", }; - if (state < ARRAY_SIZE(name)) + if (static_cast(state) < std::size(name)) { return name[state]; } diff --git a/pcsx2/USB/qemu-usb/desc.cpp b/pcsx2/USB/qemu-usb/desc.cpp index b51eb191bc..62ee4d68a4 100644 --- a/pcsx2/USB/qemu-usb/desc.cpp +++ b/pcsx2/USB/qemu-usb/desc.cpp @@ -14,10 +14,8 @@ */ #include "PrecompiledHeader.h" -#include "vl.h" -#include "desc.h" -#include "glib.h" -//#include "trace.h" +#include "USB/qemu-usb/qusb.h" +#include "USB/qemu-usb/desc.h" /* ------------------------------------------------------------------ */ diff --git a/pcsx2/USB/qemu-usb/desc.h b/pcsx2/USB/qemu-usb/desc.h index 1df5e974b2..17802bbc30 100644 --- a/pcsx2/USB/qemu-usb/desc.h +++ b/pcsx2/USB/qemu-usb/desc.h @@ -15,12 +15,11 @@ #pragma once -#include +#include #include -#include "USB/platcompat.h" /* binary representation */ -PACK( +#pragma pack(push, 1) typedef struct USBDescriptor { uint8_t bLength; uint8_t bDescriptorType; @@ -124,8 +123,8 @@ PACK( } u; } cap; } u; - }, - USBDescriptor); + } USBDescriptor; +#pragma pack(pop) struct USBDescID { diff --git a/pcsx2/USB/qemu-usb/glib.cpp b/pcsx2/USB/qemu-usb/glib.cpp deleted file mode 100644 index 222fbd94a2..0000000000 --- a/pcsx2/USB/qemu-usb/glib.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "glib.h" -#include -#include - -#define SIZE_OVERFLOWS(a, b) (G_UNLIKELY((b) > 0 && (a) > G_MAXSIZE / (b))) - -/** - * g_malloc: - * @n_bytes: the number of bytes to allocate - * - * Allocates @n_bytes bytes of memory. - * If @n_bytes is 0 it returns %NULL. - * - * Returns: a pointer to the allocated memory - */ -void* my_g_malloc(size_t n_bytes) -{ - if (G_LIKELY(n_bytes)) - { - void* mem; - - mem = malloc(n_bytes); - //TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 0)); - if (mem) - return mem; - - //g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", - // G_STRLOC, n_bytes); - } - - //TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 0, 0)); - - return NULL; -} -/** - * g_malloc0: - * @n_bytes: the number of bytes to allocate - * - * Allocates @n_bytes bytes of memory, initialized to 0's. - * If @n_bytes is 0 it returns %NULL. - * - * Returns: a pointer to the allocated memory - */ -void* my_g_malloc0(size_t n_bytes) -{ - if (G_LIKELY(n_bytes)) - { - void* mem; - - mem = calloc(1, n_bytes); - //TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 1, 0)); - if (mem) - return mem; - - //g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", - // G_STRLOC, n_bytes); - } - - //TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 1, 0)); - - return NULL; -} -/** - * g_malloc_n: - * @n_blocks: the number of blocks to allocate - * @n_block_bytes: the size of each block in bytes - * - * This function is similar to g_malloc(), allocating (@n_blocks * @n_block_bytes) bytes, - * but care is taken to detect possible overflow during multiplication. - * - * Since: 2.24 - * Returns: a pointer to the allocated memory - */ -void* my_g_malloc_n(size_t n_blocks, - size_t n_block_bytes) -{ - if (SIZE_OVERFLOWS(n_blocks, n_block_bytes)) - { - //g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes", - // G_STRLOC, n_blocks, n_block_bytes); - } - - return my_g_malloc(n_blocks * n_block_bytes); -} - -/** - * g_realloc: - * @mem: (nullable): the memory to reallocate - * @n_bytes: new size of the memory in bytes - * - * Reallocates the memory pointed to by @mem, so that it now has space for - * @n_bytes bytes of memory. It returns the new address of the memory, which may - * have been moved. @mem may be %NULL, in which case it's considered to - * have zero-length. @n_bytes may be 0, in which case %NULL will be returned - * and @mem will be freed unless it is %NULL. - * - * Returns: the new address of the allocated memory - */ -void* my_g_realloc(void* mem, - size_t n_bytes) -{ - if (G_LIKELY(n_bytes)) - { - void* newmem = realloc(mem, n_bytes); - //TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 0)); - if (newmem) - return newmem; - - //g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", - // G_STRLOC, n_bytes); - } - - if (mem) - free(mem); - - //TRACE (GLIB_MEM_REALLOC((void*) NULL, (void*)mem, 0, 0)); - - return NULL; -} - -/** - * g_realloc_n: - * @mem: (nullable): the memory to reallocate - * @n_blocks: the number of blocks to allocate - * @n_block_bytes: the size of each block in bytes - * - * This function is similar to g_realloc(), allocating (@n_blocks * @n_block_bytes) bytes, - * but care is taken to detect possible overflow during multiplication. - * - * Since: 2.24 - * Returns: the new address of the allocated memory - */ -void* my_g_realloc_n(void* mem, - size_t n_blocks, - size_t n_block_bytes) -{ - if (SIZE_OVERFLOWS(n_blocks, n_block_bytes)) - { - //g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes", - // G_STRLOC, n_blocks, n_block_bytes); - } - - return my_g_realloc(mem, n_blocks * n_block_bytes); -} diff --git a/pcsx2/USB/qemu-usb/glib.h b/pcsx2/USB/qemu-usb/glib.h deleted file mode 100644 index 3d0120ecd4..0000000000 --- a/pcsx2/USB/qemu-usb/glib.h +++ /dev/null @@ -1,47 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef GLIB_H -#define GLIB_H -#include -#include - -#define G_MAXSIZE G_MAXUINT64 - -#define G_MAXUINT64 0xffffffffffffffffUL -#define G_MAXUINT32 ((uint32_t)0xffffffff) - -void* my_g_malloc0(size_t n_bytes); -void* my_g_malloc(size_t n_bytes); -void* my_g_malloc_n(size_t n_blocks, - size_t n_block_bytes); -void* my_g_realloc_n(void* mem, - size_t n_blocks, - size_t n_block_bytes); - -#define my_g_free free - -#define G_LIKELY(expr) (expr) -#define G_UNLIKELY(expr) (expr) - -#define my_G_NEW(struct_type, n_structs, func) \ - ((struct_type*)my_g_##func##_n((n_structs), sizeof(struct_type))) -#define my_G_RENEW(struct_type, mem, n_structs, func) \ - ((struct_type*)my_g_##func##_n(mem, (n_structs), sizeof(struct_type))) - -#define my_g_new(struct_type, n_structs) my_G_NEW(struct_type, n_structs, malloc) -#define my_g_renew(struct_type, mem, n_structs) my_G_RENEW(struct_type, mem, n_structs, realloc) - -#endif diff --git a/pcsx2/USB/qemu-usb/hid.cpp b/pcsx2/USB/qemu-usb/hid.cpp index 617bbfcbd1..b330698c1e 100644 --- a/pcsx2/USB/qemu-usb/hid.cpp +++ b/pcsx2/USB/qemu-usb/hid.cpp @@ -748,14 +748,14 @@ int hid_keyboard_poll(HIDState* hs, uint8_t* buf, int len) buf[1] = 0; if (hs->kbd.keys > 6) { - memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); + memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, std::min(8, len) - 2); } else { - memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); + memcpy(buf + 2, hs->kbd.key, std::min(8, len) - 2); } - return MIN(8, len); + return std::min(8, len); } int hid_keyboard_write(HIDState* hs, uint8_t* buf, int len) diff --git a/pcsx2/USB/qemu-usb/hid.h b/pcsx2/USB/qemu-usb/hid.h index e349393c95..7e7c3c20ab 100644 --- a/pcsx2/USB/qemu-usb/hid.h +++ b/pcsx2/USB/qemu-usb/hid.h @@ -13,9 +13,8 @@ * If not, see . */ -#ifndef QEMU_HID_H -#define QEMU_HID_H -#include "vl.h" +#pragma once +#include /* include/ui/console.h */ /* keyboard/mouse support */ @@ -343,5 +342,3 @@ void hid_pointer_activate(HIDState* hs); int hid_pointer_poll(HIDState* hs, uint8_t* buf, int len); int hid_keyboard_poll(HIDState* hs, uint8_t* buf, int len); int hid_keyboard_write(HIDState* hs, uint8_t* buf, int len); - -#endif /* QEMU_HID_H */ diff --git a/pcsx2/USB/qemu-usb/input-keymap-linux-to-qcode.cpp b/pcsx2/USB/qemu-usb/input-keymap-linux-to-qcode.cpp deleted file mode 100644 index 437552f01b..0000000000 --- a/pcsx2/USB/qemu-usb/input-keymap-linux-to-qcode.cpp +++ /dev/null @@ -1,544 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "input-keymap-linux-to-qcode.h" -const QKeyCode qemu_input_map_linux_to_qcode[] = { - Q_KEY_CODE_UNMAPPED, /* linux:0 (KEY_RESERVED) -> linux:0 (KEY_RESERVED) -> qcode:Q_KEY_CODE_UNMAPPED (unmapped) */ - Q_KEY_CODE_ESC, /* linux:1 (KEY_ESC) -> linux:1 (KEY_ESC) -> qcode:Q_KEY_CODE_ESC (esc) */ - Q_KEY_CODE_1, /* linux:2 (KEY_1) -> linux:2 (KEY_1) -> qcode:Q_KEY_CODE_1 (1) */ - Q_KEY_CODE_2, /* linux:3 (KEY_2) -> linux:3 (KEY_2) -> qcode:Q_KEY_CODE_2 (2) */ - Q_KEY_CODE_3, /* linux:4 (KEY_3) -> linux:4 (KEY_3) -> qcode:Q_KEY_CODE_3 (3) */ - Q_KEY_CODE_4, /* linux:5 (KEY_4) -> linux:5 (KEY_4) -> qcode:Q_KEY_CODE_4 (4) */ - Q_KEY_CODE_5, /* linux:6 (KEY_5) -> linux:6 (KEY_5) -> qcode:Q_KEY_CODE_5 (5) */ - Q_KEY_CODE_6, /* linux:7 (KEY_6) -> linux:7 (KEY_6) -> qcode:Q_KEY_CODE_6 (6) */ - Q_KEY_CODE_7, /* linux:8 (KEY_7) -> linux:8 (KEY_7) -> qcode:Q_KEY_CODE_7 (7) */ - Q_KEY_CODE_8, /* linux:9 (KEY_8) -> linux:9 (KEY_8) -> qcode:Q_KEY_CODE_8 (8) */ - Q_KEY_CODE_9, /* linux:10 (KEY_9) -> linux:10 (KEY_9) -> qcode:Q_KEY_CODE_9 (9) */ - Q_KEY_CODE_0, /* linux:11 (KEY_0) -> linux:11 (KEY_0) -> qcode:Q_KEY_CODE_0 (0) */ - Q_KEY_CODE_MINUS, /* linux:12 (KEY_MINUS) -> linux:12 (KEY_MINUS) -> qcode:Q_KEY_CODE_MINUS (minus) */ - Q_KEY_CODE_EQUAL, /* linux:13 (KEY_EQUAL) -> linux:13 (KEY_EQUAL) -> qcode:Q_KEY_CODE_EQUAL (equal) */ - Q_KEY_CODE_BACKSPACE, /* linux:14 (KEY_BACKSPACE) -> linux:14 (KEY_BACKSPACE) -> qcode:Q_KEY_CODE_BACKSPACE (backspace) */ - Q_KEY_CODE_TAB, /* linux:15 (KEY_TAB) -> linux:15 (KEY_TAB) -> qcode:Q_KEY_CODE_TAB (tab) */ - Q_KEY_CODE_Q, /* linux:16 (KEY_Q) -> linux:16 (KEY_Q) -> qcode:Q_KEY_CODE_Q (q) */ - Q_KEY_CODE_W, /* linux:17 (KEY_W) -> linux:17 (KEY_W) -> qcode:Q_KEY_CODE_W (w) */ - Q_KEY_CODE_E, /* linux:18 (KEY_E) -> linux:18 (KEY_E) -> qcode:Q_KEY_CODE_E (e) */ - Q_KEY_CODE_R, /* linux:19 (KEY_R) -> linux:19 (KEY_R) -> qcode:Q_KEY_CODE_R (r) */ - Q_KEY_CODE_T, /* linux:20 (KEY_T) -> linux:20 (KEY_T) -> qcode:Q_KEY_CODE_T (t) */ - Q_KEY_CODE_Y, /* linux:21 (KEY_Y) -> linux:21 (KEY_Y) -> qcode:Q_KEY_CODE_Y (y) */ - Q_KEY_CODE_U, /* linux:22 (KEY_U) -> linux:22 (KEY_U) -> qcode:Q_KEY_CODE_U (u) */ - Q_KEY_CODE_I, /* linux:23 (KEY_I) -> linux:23 (KEY_I) -> qcode:Q_KEY_CODE_I (i) */ - Q_KEY_CODE_O, /* linux:24 (KEY_O) -> linux:24 (KEY_O) -> qcode:Q_KEY_CODE_O (o) */ - Q_KEY_CODE_P, /* linux:25 (KEY_P) -> linux:25 (KEY_P) -> qcode:Q_KEY_CODE_P (p) */ - Q_KEY_CODE_BRACKET_LEFT, /* linux:26 (KEY_LEFTBRACE) -> linux:26 (KEY_LEFTBRACE) -> qcode:Q_KEY_CODE_BRACKET_LEFT (bracket_left) */ - Q_KEY_CODE_BRACKET_RIGHT, /* linux:27 (KEY_RIGHTBRACE) -> linux:27 (KEY_RIGHTBRACE) -> qcode:Q_KEY_CODE_BRACKET_RIGHT (bracket_right) */ - Q_KEY_CODE_RET, /* linux:28 (KEY_ENTER) -> linux:28 (KEY_ENTER) -> qcode:Q_KEY_CODE_RET (ret) */ - Q_KEY_CODE_CTRL, /* linux:29 (KEY_LEFTCTRL) -> linux:29 (KEY_LEFTCTRL) -> qcode:Q_KEY_CODE_CTRL (ctrl) */ - Q_KEY_CODE_A, /* linux:30 (KEY_A) -> linux:30 (KEY_A) -> qcode:Q_KEY_CODE_A (a) */ - Q_KEY_CODE_S, /* linux:31 (KEY_S) -> linux:31 (KEY_S) -> qcode:Q_KEY_CODE_S (s) */ - Q_KEY_CODE_D, /* linux:32 (KEY_D) -> linux:32 (KEY_D) -> qcode:Q_KEY_CODE_D (d) */ - Q_KEY_CODE_F, /* linux:33 (KEY_F) -> linux:33 (KEY_F) -> qcode:Q_KEY_CODE_F (f) */ - Q_KEY_CODE_G, /* linux:34 (KEY_G) -> linux:34 (KEY_G) -> qcode:Q_KEY_CODE_G (g) */ - Q_KEY_CODE_H, /* linux:35 (KEY_H) -> linux:35 (KEY_H) -> qcode:Q_KEY_CODE_H (h) */ - Q_KEY_CODE_J, /* linux:36 (KEY_J) -> linux:36 (KEY_J) -> qcode:Q_KEY_CODE_J (j) */ - Q_KEY_CODE_K, /* linux:37 (KEY_K) -> linux:37 (KEY_K) -> qcode:Q_KEY_CODE_K (k) */ - Q_KEY_CODE_L, /* linux:38 (KEY_L) -> linux:38 (KEY_L) -> qcode:Q_KEY_CODE_L (l) */ - Q_KEY_CODE_SEMICOLON, /* linux:39 (KEY_SEMICOLON) -> linux:39 (KEY_SEMICOLON) -> qcode:Q_KEY_CODE_SEMICOLON (semicolon) */ - Q_KEY_CODE_APOSTROPHE, /* linux:40 (KEY_APOSTROPHE) -> linux:40 (KEY_APOSTROPHE) -> qcode:Q_KEY_CODE_APOSTROPHE (apostrophe) */ - Q_KEY_CODE_GRAVE_ACCENT, /* linux:41 (KEY_GRAVE) -> linux:41 (KEY_GRAVE) -> qcode:Q_KEY_CODE_GRAVE_ACCENT (grave_accent) */ - Q_KEY_CODE_SHIFT, /* linux:42 (KEY_LEFTSHIFT) -> linux:42 (KEY_LEFTSHIFT) -> qcode:Q_KEY_CODE_SHIFT (shift) */ - Q_KEY_CODE_BACKSLASH, /* linux:43 (KEY_BACKSLASH) -> linux:43 (KEY_BACKSLASH) -> qcode:Q_KEY_CODE_BACKSLASH (backslash) */ - Q_KEY_CODE_Z, /* linux:44 (KEY_Z) -> linux:44 (KEY_Z) -> qcode:Q_KEY_CODE_Z (z) */ - Q_KEY_CODE_X, /* linux:45 (KEY_X) -> linux:45 (KEY_X) -> qcode:Q_KEY_CODE_X (x) */ - Q_KEY_CODE_C, /* linux:46 (KEY_C) -> linux:46 (KEY_C) -> qcode:Q_KEY_CODE_C (c) */ - Q_KEY_CODE_V, /* linux:47 (KEY_V) -> linux:47 (KEY_V) -> qcode:Q_KEY_CODE_V (v) */ - Q_KEY_CODE_B, /* linux:48 (KEY_B) -> linux:48 (KEY_B) -> qcode:Q_KEY_CODE_B (b) */ - Q_KEY_CODE_N, /* linux:49 (KEY_N) -> linux:49 (KEY_N) -> qcode:Q_KEY_CODE_N (n) */ - Q_KEY_CODE_M, /* linux:50 (KEY_M) -> linux:50 (KEY_M) -> qcode:Q_KEY_CODE_M (m) */ - Q_KEY_CODE_COMMA, /* linux:51 (KEY_COMMA) -> linux:51 (KEY_COMMA) -> qcode:Q_KEY_CODE_COMMA (comma) */ - Q_KEY_CODE_DOT, /* linux:52 (KEY_DOT) -> linux:52 (KEY_DOT) -> qcode:Q_KEY_CODE_DOT (dot) */ - Q_KEY_CODE_SLASH, /* linux:53 (KEY_SLASH) -> linux:53 (KEY_SLASH) -> qcode:Q_KEY_CODE_SLASH (slash) */ - Q_KEY_CODE_SHIFT_R, /* linux:54 (KEY_RIGHTSHIFT) -> linux:54 (KEY_RIGHTSHIFT) -> qcode:Q_KEY_CODE_SHIFT_R (shift_r) */ - Q_KEY_CODE_KP_MULTIPLY, /* linux:55 (KEY_KPASTERISK) -> linux:55 (KEY_KPASTERISK) -> qcode:Q_KEY_CODE_KP_MULTIPLY (kp_multiply) */ - Q_KEY_CODE_ALT, /* linux:56 (KEY_LEFTALT) -> linux:56 (KEY_LEFTALT) -> qcode:Q_KEY_CODE_ALT (alt) */ - Q_KEY_CODE_SPC, /* linux:57 (KEY_SPACE) -> linux:57 (KEY_SPACE) -> qcode:Q_KEY_CODE_SPC (spc) */ - Q_KEY_CODE_CAPS_LOCK, /* linux:58 (KEY_CAPSLOCK) -> linux:58 (KEY_CAPSLOCK) -> qcode:Q_KEY_CODE_CAPS_LOCK (caps_lock) */ - Q_KEY_CODE_F1, /* linux:59 (KEY_F1) -> linux:59 (KEY_F1) -> qcode:Q_KEY_CODE_F1 (f1) */ - Q_KEY_CODE_F2, /* linux:60 (KEY_F2) -> linux:60 (KEY_F2) -> qcode:Q_KEY_CODE_F2 (f2) */ - Q_KEY_CODE_F3, /* linux:61 (KEY_F3) -> linux:61 (KEY_F3) -> qcode:Q_KEY_CODE_F3 (f3) */ - Q_KEY_CODE_F4, /* linux:62 (KEY_F4) -> linux:62 (KEY_F4) -> qcode:Q_KEY_CODE_F4 (f4) */ - Q_KEY_CODE_F5, /* linux:63 (KEY_F5) -> linux:63 (KEY_F5) -> qcode:Q_KEY_CODE_F5 (f5) */ - Q_KEY_CODE_F6, /* linux:64 (KEY_F6) -> linux:64 (KEY_F6) -> qcode:Q_KEY_CODE_F6 (f6) */ - Q_KEY_CODE_F7, /* linux:65 (KEY_F7) -> linux:65 (KEY_F7) -> qcode:Q_KEY_CODE_F7 (f7) */ - Q_KEY_CODE_F8, /* linux:66 (KEY_F8) -> linux:66 (KEY_F8) -> qcode:Q_KEY_CODE_F8 (f8) */ - Q_KEY_CODE_F9, /* linux:67 (KEY_F9) -> linux:67 (KEY_F9) -> qcode:Q_KEY_CODE_F9 (f9) */ - Q_KEY_CODE_F10, /* linux:68 (KEY_F10) -> linux:68 (KEY_F10) -> qcode:Q_KEY_CODE_F10 (f10) */ - Q_KEY_CODE_NUM_LOCK, /* linux:69 (KEY_NUMLOCK) -> linux:69 (KEY_NUMLOCK) -> qcode:Q_KEY_CODE_NUM_LOCK (num_lock) */ - Q_KEY_CODE_SCROLL_LOCK, /* linux:70 (KEY_SCROLLLOCK) -> linux:70 (KEY_SCROLLLOCK) -> qcode:Q_KEY_CODE_SCROLL_LOCK (scroll_lock) */ - Q_KEY_CODE_KP_7, /* linux:71 (KEY_KP7) -> linux:71 (KEY_KP7) -> qcode:Q_KEY_CODE_KP_7 (kp_7) */ - Q_KEY_CODE_KP_8, /* linux:72 (KEY_KP8) -> linux:72 (KEY_KP8) -> qcode:Q_KEY_CODE_KP_8 (kp_8) */ - Q_KEY_CODE_KP_9, /* linux:73 (KEY_KP9) -> linux:73 (KEY_KP9) -> qcode:Q_KEY_CODE_KP_9 (kp_9) */ - Q_KEY_CODE_KP_SUBTRACT, /* linux:74 (KEY_KPMINUS) -> linux:74 (KEY_KPMINUS) -> qcode:Q_KEY_CODE_KP_SUBTRACT (kp_subtract) */ - Q_KEY_CODE_KP_4, /* linux:75 (KEY_KP4) -> linux:75 (KEY_KP4) -> qcode:Q_KEY_CODE_KP_4 (kp_4) */ - Q_KEY_CODE_KP_5, /* linux:76 (KEY_KP5) -> linux:76 (KEY_KP5) -> qcode:Q_KEY_CODE_KP_5 (kp_5) */ - Q_KEY_CODE_KP_6, /* linux:77 (KEY_KP6) -> linux:77 (KEY_KP6) -> qcode:Q_KEY_CODE_KP_6 (kp_6) */ - Q_KEY_CODE_KP_ADD, /* linux:78 (KEY_KPPLUS) -> linux:78 (KEY_KPPLUS) -> qcode:Q_KEY_CODE_KP_ADD (kp_add) */ - Q_KEY_CODE_KP_1, /* linux:79 (KEY_KP1) -> linux:79 (KEY_KP1) -> qcode:Q_KEY_CODE_KP_1 (kp_1) */ - Q_KEY_CODE_KP_2, /* linux:80 (KEY_KP2) -> linux:80 (KEY_KP2) -> qcode:Q_KEY_CODE_KP_2 (kp_2) */ - Q_KEY_CODE_KP_3, /* linux:81 (KEY_KP3) -> linux:81 (KEY_KP3) -> qcode:Q_KEY_CODE_KP_3 (kp_3) */ - Q_KEY_CODE_KP_0, /* linux:82 (KEY_KP0) -> linux:82 (KEY_KP0) -> qcode:Q_KEY_CODE_KP_0 (kp_0) */ - Q_KEY_CODE_KP_DECIMAL, /* linux:83 (KEY_KPDOT) -> linux:83 (KEY_KPDOT) -> qcode:Q_KEY_CODE_KP_DECIMAL (kp_decimal) */ - Q_KEY_CODE_UNMAPPED, /* linux:84 (unnamed) -> linux:84 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:85 (KEY_ZENKAKUHANKAKU) -> linux:85 (KEY_ZENKAKUHANKAKU) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_LESS, /* linux:86 (KEY_102ND) -> linux:86 (KEY_102ND) -> qcode:Q_KEY_CODE_LESS (less) */ - Q_KEY_CODE_F11, /* linux:87 (KEY_F11) -> linux:87 (KEY_F11) -> qcode:Q_KEY_CODE_F11 (f11) */ - Q_KEY_CODE_F12, /* linux:88 (KEY_F12) -> linux:88 (KEY_F12) -> qcode:Q_KEY_CODE_F12 (f12) */ - Q_KEY_CODE_RO, /* linux:89 (KEY_RO) -> linux:89 (KEY_RO) -> qcode:Q_KEY_CODE_RO (ro) */ - Q_KEY_CODE_UNMAPPED, /* linux:90 (KEY_KATAKANA) -> linux:90 (KEY_KATAKANA) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_HIRAGANA, /* linux:91 (KEY_HIRAGANA) -> linux:91 (KEY_HIRAGANA) -> qcode:Q_KEY_CODE_HIRAGANA (hiragana) */ - Q_KEY_CODE_HENKAN, /* linux:92 (KEY_HENKAN) -> linux:92 (KEY_HENKAN) -> qcode:Q_KEY_CODE_HENKAN (henkan) */ - Q_KEY_CODE_KATAKANAHIRAGANA, /* linux:93 (KEY_KATAKANAHIRAGANA) -> linux:93 (KEY_KATAKANAHIRAGANA) -> qcode:Q_KEY_CODE_KATAKANAHIRAGANA (katakanahiragana) */ - Q_KEY_CODE_MUHENKAN, /* linux:94 (KEY_MUHENKAN) -> linux:94 (KEY_MUHENKAN) -> qcode:Q_KEY_CODE_MUHENKAN (muhenkan) */ - Q_KEY_CODE_UNMAPPED, /* linux:95 (KEY_KPJPCOMMA) -> linux:95 (KEY_KPJPCOMMA) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_KP_ENTER, /* linux:96 (KEY_KPENTER) -> linux:96 (KEY_KPENTER) -> qcode:Q_KEY_CODE_KP_ENTER (kp_enter) */ - Q_KEY_CODE_CTRL_R, /* linux:97 (KEY_RIGHTCTRL) -> linux:97 (KEY_RIGHTCTRL) -> qcode:Q_KEY_CODE_CTRL_R (ctrl_r) */ - Q_KEY_CODE_KP_DIVIDE, /* linux:98 (KEY_KPSLASH) -> linux:98 (KEY_KPSLASH) -> qcode:Q_KEY_CODE_KP_DIVIDE (kp_divide) */ - Q_KEY_CODE_SYSRQ, /* linux:99 (KEY_SYSRQ) -> linux:99 (KEY_SYSRQ) -> qcode:Q_KEY_CODE_SYSRQ (sysrq) */ - Q_KEY_CODE_ALT_R, /* linux:100 (KEY_RIGHTALT) -> linux:100 (KEY_RIGHTALT) -> qcode:Q_KEY_CODE_ALT_R (alt_r) */ - Q_KEY_CODE_LF, /* linux:101 (KEY_LINEFEED) -> linux:101 (KEY_LINEFEED) -> qcode:Q_KEY_CODE_LF (lf) */ - Q_KEY_CODE_HOME, /* linux:102 (KEY_HOME) -> linux:102 (KEY_HOME) -> qcode:Q_KEY_CODE_HOME (home) */ - Q_KEY_CODE_UP, /* linux:103 (KEY_UP) -> linux:103 (KEY_UP) -> qcode:Q_KEY_CODE_UP (up) */ - Q_KEY_CODE_PGUP, /* linux:104 (KEY_PAGEUP) -> linux:104 (KEY_PAGEUP) -> qcode:Q_KEY_CODE_PGUP (pgup) */ - Q_KEY_CODE_LEFT, /* linux:105 (KEY_LEFT) -> linux:105 (KEY_LEFT) -> qcode:Q_KEY_CODE_LEFT (left) */ - Q_KEY_CODE_RIGHT, /* linux:106 (KEY_RIGHT) -> linux:106 (KEY_RIGHT) -> qcode:Q_KEY_CODE_RIGHT (right) */ - Q_KEY_CODE_END, /* linux:107 (KEY_END) -> linux:107 (KEY_END) -> qcode:Q_KEY_CODE_END (end) */ - Q_KEY_CODE_DOWN, /* linux:108 (KEY_DOWN) -> linux:108 (KEY_DOWN) -> qcode:Q_KEY_CODE_DOWN (down) */ - Q_KEY_CODE_PGDN, /* linux:109 (KEY_PAGEDOWN) -> linux:109 (KEY_PAGEDOWN) -> qcode:Q_KEY_CODE_PGDN (pgdn) */ - Q_KEY_CODE_INSERT, /* linux:110 (KEY_INSERT) -> linux:110 (KEY_INSERT) -> qcode:Q_KEY_CODE_INSERT (insert) */ - Q_KEY_CODE_DELETE, /* linux:111 (KEY_DELETE) -> linux:111 (KEY_DELETE) -> qcode:Q_KEY_CODE_DELETE (delete) */ - Q_KEY_CODE_UNMAPPED, /* linux:112 (KEY_MACRO) -> linux:112 (KEY_MACRO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_AUDIOMUTE, /* linux:113 (KEY_MUTE) -> linux:113 (KEY_MUTE) -> qcode:Q_KEY_CODE_AUDIOMUTE (audiomute) */ - Q_KEY_CODE_VOLUMEDOWN, /* linux:114 (KEY_VOLUMEDOWN) -> linux:114 (KEY_VOLUMEDOWN) -> qcode:Q_KEY_CODE_VOLUMEDOWN (volumedown) */ - Q_KEY_CODE_VOLUMEUP, /* linux:115 (KEY_VOLUMEUP) -> linux:115 (KEY_VOLUMEUP) -> qcode:Q_KEY_CODE_VOLUMEUP (volumeup) */ - Q_KEY_CODE_POWER, /* linux:116 (KEY_POWER) -> linux:116 (KEY_POWER) -> qcode:Q_KEY_CODE_POWER (power) */ - Q_KEY_CODE_KP_EQUALS, /* linux:117 (KEY_KPEQUAL) -> linux:117 (KEY_KPEQUAL) -> qcode:Q_KEY_CODE_KP_EQUALS (kp_equals) */ - Q_KEY_CODE_UNMAPPED, /* linux:118 (KEY_KPPLUSMINUS) -> linux:118 (KEY_KPPLUSMINUS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_PAUSE, /* linux:119 (KEY_PAUSE) -> linux:119 (KEY_PAUSE) -> qcode:Q_KEY_CODE_PAUSE (pause) */ - Q_KEY_CODE_UNMAPPED, /* linux:120 (KEY_SCALE) -> linux:120 (KEY_SCALE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_KP_COMMA, /* linux:121 (KEY_KPCOMMA) -> linux:121 (KEY_KPCOMMA) -> qcode:Q_KEY_CODE_KP_COMMA (kp_comma) */ - Q_KEY_CODE_UNMAPPED, /* linux:122 (KEY_HANGEUL) -> linux:122 (KEY_HANGEUL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:123 (KEY_HANJA) -> linux:123 (KEY_HANJA) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_YEN, /* linux:124 (KEY_YEN) -> linux:124 (KEY_YEN) -> qcode:Q_KEY_CODE_YEN (yen) */ - Q_KEY_CODE_META_L, /* linux:125 (KEY_LEFTMETA) -> linux:125 (KEY_LEFTMETA) -> qcode:Q_KEY_CODE_META_L (meta_l) */ - Q_KEY_CODE_META_R, /* linux:126 (KEY_RIGHTMETA) -> linux:126 (KEY_RIGHTMETA) -> qcode:Q_KEY_CODE_META_R (meta_r) */ - Q_KEY_CODE_COMPOSE, /* linux:127 (KEY_COMPOSE) -> linux:127 (KEY_COMPOSE) -> qcode:Q_KEY_CODE_COMPOSE (compose) */ - Q_KEY_CODE_STOP, /* linux:128 (KEY_STOP) -> linux:128 (KEY_STOP) -> qcode:Q_KEY_CODE_STOP (stop) */ - Q_KEY_CODE_AGAIN, /* linux:129 (KEY_AGAIN) -> linux:129 (KEY_AGAIN) -> qcode:Q_KEY_CODE_AGAIN (again) */ - Q_KEY_CODE_PROPS, /* linux:130 (KEY_PROPS) -> linux:130 (KEY_PROPS) -> qcode:Q_KEY_CODE_PROPS (props) */ - Q_KEY_CODE_UNDO, /* linux:131 (KEY_UNDO) -> linux:131 (KEY_UNDO) -> qcode:Q_KEY_CODE_UNDO (undo) */ - Q_KEY_CODE_FRONT, /* linux:132 (KEY_FRONT) -> linux:132 (KEY_FRONT) -> qcode:Q_KEY_CODE_FRONT (front) */ - Q_KEY_CODE_COPY, /* linux:133 (KEY_COPY) -> linux:133 (KEY_COPY) -> qcode:Q_KEY_CODE_COPY (copy) */ - Q_KEY_CODE_OPEN, /* linux:134 (KEY_OPEN) -> linux:134 (KEY_OPEN) -> qcode:Q_KEY_CODE_OPEN (open) */ - Q_KEY_CODE_PASTE, /* linux:135 (KEY_PASTE) -> linux:135 (KEY_PASTE) -> qcode:Q_KEY_CODE_PASTE (paste) */ - Q_KEY_CODE_FIND, /* linux:136 (KEY_FIND) -> linux:136 (KEY_FIND) -> qcode:Q_KEY_CODE_FIND (find) */ - Q_KEY_CODE_CUT, /* linux:137 (KEY_CUT) -> linux:137 (KEY_CUT) -> qcode:Q_KEY_CODE_CUT (cut) */ - Q_KEY_CODE_HELP, /* linux:138 (KEY_HELP) -> linux:138 (KEY_HELP) -> qcode:Q_KEY_CODE_HELP (help) */ - Q_KEY_CODE_MENU, /* linux:139 (KEY_MENU) -> linux:139 (KEY_MENU) -> qcode:Q_KEY_CODE_MENU (menu) */ - Q_KEY_CODE_CALCULATOR, /* linux:140 (KEY_CALC) -> linux:140 (KEY_CALC) -> qcode:Q_KEY_CODE_CALCULATOR (calculator) */ - Q_KEY_CODE_UNMAPPED, /* linux:141 (KEY_SETUP) -> linux:141 (KEY_SETUP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_SLEEP, /* linux:142 (KEY_SLEEP) -> linux:142 (KEY_SLEEP) -> qcode:Q_KEY_CODE_SLEEP (sleep) */ - Q_KEY_CODE_WAKE, /* linux:143 (KEY_WAKEUP) -> linux:143 (KEY_WAKEUP) -> qcode:Q_KEY_CODE_WAKE (wake) */ - Q_KEY_CODE_UNMAPPED, /* linux:144 (KEY_FILE) -> linux:144 (KEY_FILE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:145 (KEY_SENDFILE) -> linux:145 (KEY_SENDFILE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:146 (KEY_DELETEFILE) -> linux:146 (KEY_DELETEFILE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:147 (KEY_XFER) -> linux:147 (KEY_XFER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:148 (KEY_PROG1) -> linux:148 (KEY_PROG1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:149 (KEY_PROG2) -> linux:149 (KEY_PROG2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:150 (KEY_WWW) -> linux:150 (KEY_WWW) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:151 (KEY_MSDOS) -> linux:151 (KEY_MSDOS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:152 (KEY_SCREENLOCK) -> linux:152 (KEY_SCREENLOCK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:153 (KEY_DIRECTION) -> linux:153 (KEY_DIRECTION) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:154 (KEY_CYCLEWINDOWS) -> linux:154 (KEY_CYCLEWINDOWS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_MAIL, /* linux:155 (KEY_MAIL) -> linux:155 (KEY_MAIL) -> qcode:Q_KEY_CODE_MAIL (mail) */ - Q_KEY_CODE_AC_BOOKMARKS, /* linux:156 (KEY_BOOKMARKS) -> linux:156 (KEY_BOOKMARKS) -> qcode:Q_KEY_CODE_AC_BOOKMARKS (ac_bookmarks) */ - Q_KEY_CODE_COMPUTER, /* linux:157 (KEY_COMPUTER) -> linux:157 (KEY_COMPUTER) -> qcode:Q_KEY_CODE_COMPUTER (computer) */ - Q_KEY_CODE_AC_BACK, /* linux:158 (KEY_BACK) -> linux:158 (KEY_BACK) -> qcode:Q_KEY_CODE_AC_BACK (ac_back) */ - Q_KEY_CODE_AC_FORWARD, /* linux:159 (KEY_FORWARD) -> linux:159 (KEY_FORWARD) -> qcode:Q_KEY_CODE_AC_FORWARD (ac_forward) */ - Q_KEY_CODE_UNMAPPED, /* linux:160 (KEY_CLOSECD) -> linux:160 (KEY_CLOSECD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:161 (KEY_EJECTCD) -> linux:161 (KEY_EJECTCD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:162 (KEY_EJECTCLOSECD) -> linux:162 (KEY_EJECTCLOSECD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_AUDIONEXT, /* linux:163 (KEY_NEXTSONG) -> linux:163 (KEY_NEXTSONG) -> qcode:Q_KEY_CODE_AUDIONEXT (audionext) */ - Q_KEY_CODE_AUDIOPLAY, /* linux:164 (KEY_PLAYPAUSE) -> linux:164 (KEY_PLAYPAUSE) -> qcode:Q_KEY_CODE_AUDIOPLAY (audioplay) */ - Q_KEY_CODE_AUDIOPREV, /* linux:165 (KEY_PREVIOUSSONG) -> linux:165 (KEY_PREVIOUSSONG) -> qcode:Q_KEY_CODE_AUDIOPREV (audioprev) */ - Q_KEY_CODE_AUDIOSTOP, /* linux:166 (KEY_STOPCD) -> linux:166 (KEY_STOPCD) -> qcode:Q_KEY_CODE_AUDIOSTOP (audiostop) */ - Q_KEY_CODE_UNMAPPED, /* linux:167 (KEY_RECORD) -> linux:167 (KEY_RECORD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:168 (KEY_REWIND) -> linux:168 (KEY_REWIND) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:169 (KEY_PHONE) -> linux:169 (KEY_PHONE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:170 (KEY_ISO) -> linux:170 (KEY_ISO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:171 (KEY_CONFIG) -> linux:171 (KEY_CONFIG) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_AC_HOME, /* linux:172 (KEY_HOMEPAGE) -> linux:172 (KEY_HOMEPAGE) -> qcode:Q_KEY_CODE_AC_HOME (ac_home) */ - Q_KEY_CODE_AC_REFRESH, /* linux:173 (KEY_REFRESH) -> linux:173 (KEY_REFRESH) -> qcode:Q_KEY_CODE_AC_REFRESH (ac_refresh) */ - Q_KEY_CODE_UNMAPPED, /* linux:174 (KEY_EXIT) -> linux:174 (KEY_EXIT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:175 (KEY_MOVE) -> linux:175 (KEY_MOVE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:176 (KEY_EDIT) -> linux:176 (KEY_EDIT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:177 (KEY_SCROLLUP) -> linux:177 (KEY_SCROLLUP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:178 (KEY_SCROLLDOWN) -> linux:178 (KEY_SCROLLDOWN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:179 (KEY_KPLEFTPAREN) -> linux:179 (KEY_KPLEFTPAREN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:180 (KEY_KPRIGHTPAREN) -> linux:180 (KEY_KPRIGHTPAREN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:181 (KEY_NEW) -> linux:181 (KEY_NEW) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:182 (KEY_REDO) -> linux:182 (KEY_REDO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:183 (KEY_F13) -> linux:183 (KEY_F13) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:184 (KEY_F14) -> linux:184 (KEY_F14) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:185 (KEY_F15) -> linux:185 (KEY_F15) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:186 (KEY_F16) -> linux:186 (KEY_F16) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:187 (KEY_F17) -> linux:187 (KEY_F17) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:188 (KEY_F18) -> linux:188 (KEY_F18) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:189 (KEY_F19) -> linux:189 (KEY_F19) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:190 (KEY_F20) -> linux:190 (KEY_F20) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:191 (KEY_F21) -> linux:191 (KEY_F21) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:192 (KEY_F22) -> linux:192 (KEY_F22) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:193 (KEY_F23) -> linux:193 (KEY_F23) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:194 (KEY_F24) -> linux:194 (KEY_F24) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:195 (unnamed) -> linux:195 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:196 (unnamed) -> linux:196 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:197 (unnamed) -> linux:197 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:198 (unnamed) -> linux:198 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:199 (unnamed) -> linux:199 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:200 (KEY_PLAYCD) -> linux:200 (KEY_PLAYCD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:201 (KEY_PAUSECD) -> linux:201 (KEY_PAUSECD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:202 (KEY_PROG3) -> linux:202 (KEY_PROG3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:203 (KEY_PROG4) -> linux:203 (KEY_PROG4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:204 (KEY_DASHBOARD) -> linux:204 (KEY_DASHBOARD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:205 (KEY_SUSPEND) -> linux:205 (KEY_SUSPEND) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:206 (KEY_CLOSE) -> linux:206 (KEY_CLOSE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:207 (KEY_PLAY) -> linux:207 (KEY_PLAY) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:208 (KEY_FASTFORWARD) -> linux:208 (KEY_FASTFORWARD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:209 (KEY_BASSBOOST) -> linux:209 (KEY_BASSBOOST) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:210 (KEY_PRINT) -> linux:210 (KEY_PRINT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:211 (KEY_HP) -> linux:211 (KEY_HP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:212 (KEY_CAMERA) -> linux:212 (KEY_CAMERA) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:213 (KEY_SOUND) -> linux:213 (KEY_SOUND) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:214 (KEY_QUESTION) -> linux:214 (KEY_QUESTION) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:215 (KEY_EMAIL) -> linux:215 (KEY_EMAIL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:216 (KEY_CHAT) -> linux:216 (KEY_CHAT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:217 (KEY_SEARCH) -> linux:217 (KEY_SEARCH) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:218 (KEY_CONNECT) -> linux:218 (KEY_CONNECT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:219 (KEY_FINANCE) -> linux:219 (KEY_FINANCE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:220 (KEY_SPORT) -> linux:220 (KEY_SPORT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:221 (KEY_SHOP) -> linux:221 (KEY_SHOP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:222 (KEY_ALTERASE) -> linux:222 (KEY_ALTERASE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:223 (KEY_CANCEL) -> linux:223 (KEY_CANCEL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:224 (KEY_BRIGHTNESSDOWN) -> linux:224 (KEY_BRIGHTNESSDOWN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:225 (KEY_BRIGHTNESSUP) -> linux:225 (KEY_BRIGHTNESSUP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_MEDIASELECT, /* linux:226 (KEY_MEDIA) -> linux:226 (KEY_MEDIA) -> qcode:Q_KEY_CODE_MEDIASELECT (mediaselect) */ - Q_KEY_CODE_UNMAPPED, /* linux:227 (KEY_SWITCHVIDEOMODE) -> linux:227 (KEY_SWITCHVIDEOMODE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:228 (KEY_KBDILLUMTOGGLE) -> linux:228 (KEY_KBDILLUMTOGGLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:229 (KEY_KBDILLUMDOWN) -> linux:229 (KEY_KBDILLUMDOWN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:230 (KEY_KBDILLUMUP) -> linux:230 (KEY_KBDILLUMUP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:231 (KEY_SEND) -> linux:231 (KEY_SEND) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:232 (KEY_REPLY) -> linux:232 (KEY_REPLY) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:233 (KEY_FORWARDMAIL) -> linux:233 (KEY_FORWARDMAIL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:234 (KEY_SAVE) -> linux:234 (KEY_SAVE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:235 (KEY_DOCUMENTS) -> linux:235 (KEY_DOCUMENTS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:236 (KEY_BATTERY) -> linux:236 (KEY_BATTERY) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:237 (KEY_BLUETOOTH) -> linux:237 (KEY_BLUETOOTH) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:238 (KEY_WLAN) -> linux:238 (KEY_WLAN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:239 (KEY_UWB) -> linux:239 (KEY_UWB) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:240 (KEY_UNKNOWN) -> linux:240 (KEY_UNKNOWN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:241 (KEY_VIDEO_NEXT) -> linux:241 (KEY_VIDEO_NEXT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:242 (KEY_VIDEO_PREV) -> linux:242 (KEY_VIDEO_PREV) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:243 (KEY_BRIGHTNESS_CYCLE) -> linux:243 (KEY_BRIGHTNESS_CYCLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:244 (KEY_BRIGHTNESS_ZERO) -> linux:244 (KEY_BRIGHTNESS_ZERO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:245 (KEY_DISPLAY_OFF) -> linux:245 (KEY_DISPLAY_OFF) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:246 (KEY_WIMAX) -> linux:246 (KEY_WIMAX) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:247 (unnamed) -> linux:247 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:248 (unnamed) -> linux:248 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:249 (unnamed) -> linux:249 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:250 (unnamed) -> linux:250 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:251 (unnamed) -> linux:251 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:252 (unnamed) -> linux:252 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:253 (unnamed) -> linux:253 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:254 (unnamed) -> linux:254 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:255 (unnamed) -> linux:255 (unnamed) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:256 (BTN_0) -> linux:256 (BTN_0) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:257 (BTN_1) -> linux:257 (BTN_1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:258 (BTN_2) -> linux:258 (BTN_2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:259 (BTN_3) -> linux:259 (BTN_3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:260 (BTN_4) -> linux:260 (BTN_4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:261 (BTN_5) -> linux:261 (BTN_5) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:262 (BTN_6) -> linux:262 (BTN_6) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:263 (BTN_7) -> linux:263 (BTN_7) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:264 (BTN_8) -> linux:264 (BTN_8) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:265 (BTN_9) -> linux:265 (BTN_9) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:266 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:267 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:268 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:269 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:270 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:271 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:272 (BTN_LEFT) -> linux:272 (BTN_LEFT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:273 (BTN_RIGHT) -> linux:273 (BTN_RIGHT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:274 (BTN_MIDDLE) -> linux:274 (BTN_MIDDLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:275 (BTN_SIDE) -> linux:275 (BTN_SIDE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:276 (BTN_EXTRA) -> linux:276 (BTN_EXTRA) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:277 (BTN_FORWARD) -> linux:277 (BTN_FORWARD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:278 (BTN_BACK) -> linux:278 (BTN_BACK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:279 (BTN_TASK) -> linux:279 (BTN_TASK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:280 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:281 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:282 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:283 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:284 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:285 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:286 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:287 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:288 (BTN_TRIGGER) -> linux:288 (BTN_TRIGGER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:289 (BTN_THUMB) -> linux:289 (BTN_THUMB) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:290 (BTN_THUMB2) -> linux:290 (BTN_THUMB2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:291 (BTN_TOP) -> linux:291 (BTN_TOP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:292 (BTN_TOP2) -> linux:292 (BTN_TOP2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:293 (BTN_PINKIE) -> linux:293 (BTN_PINKIE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:294 (BTN_BASE) -> linux:294 (BTN_BASE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:295 (BTN_BASE2) -> linux:295 (BTN_BASE2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:296 (BTN_BASE3) -> linux:296 (BTN_BASE3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:297 (BTN_BASE4) -> linux:297 (BTN_BASE4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:298 (BTN_BASE5) -> linux:298 (BTN_BASE5) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:299 (BTN_BASE6) -> linux:299 (BTN_BASE6) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:300 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:301 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:302 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:303 (BTN_DEAD) -> linux:303 (BTN_DEAD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:304 (BTN_A) -> linux:304 (BTN_A) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:305 (BTN_B) -> linux:305 (BTN_B) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:306 (BTN_C) -> linux:306 (BTN_C) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:307 (BTN_X) -> linux:307 (BTN_X) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:308 (BTN_Y) -> linux:308 (BTN_Y) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:309 (BTN_Z) -> linux:309 (BTN_Z) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:310 (BTN_TL) -> linux:310 (BTN_TL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:311 (BTN_TR) -> linux:311 (BTN_TR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:312 (BTN_TL2) -> linux:312 (BTN_TL2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:313 (BTN_TR2) -> linux:313 (BTN_TR2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:314 (BTN_SELECT) -> linux:314 (BTN_SELECT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:315 (BTN_START) -> linux:315 (BTN_START) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:316 (BTN_MODE) -> linux:316 (BTN_MODE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:317 (BTN_THUMBL) -> linux:317 (BTN_THUMBL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:318 (BTN_THUMBR) -> linux:318 (BTN_THUMBR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:319 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:320 (BTN_TOOL_PEN) -> linux:320 (BTN_TOOL_PEN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:321 (BTN_TOOL_RUBBER) -> linux:321 (BTN_TOOL_RUBBER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:322 (BTN_TOOL_BRUSH) -> linux:322 (BTN_TOOL_BRUSH) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:323 (BTN_TOOL_PENCIL) -> linux:323 (BTN_TOOL_PENCIL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:324 (BTN_TOOL_AIRBRUSH) -> linux:324 (BTN_TOOL_AIRBRUSH) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:325 (BTN_TOOL_FINGER) -> linux:325 (BTN_TOOL_FINGER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:326 (BTN_TOOL_MOUSE) -> linux:326 (BTN_TOOL_MOUSE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:327 (BTN_TOOL_LENS) -> linux:327 (BTN_TOOL_LENS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:328 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:329 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:330 (BTN_TOUCH) -> linux:330 (BTN_TOUCH) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:331 (BTN_STYLUS) -> linux:331 (BTN_STYLUS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:332 (BTN_STYLUS2) -> linux:332 (BTN_STYLUS2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:333 (BTN_TOOL_DOUBLETAP) -> linux:333 (BTN_TOOL_DOUBLETAP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:334 (BTN_TOOL_TRIPLETAP) -> linux:334 (BTN_TOOL_TRIPLETAP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:335 (BTN_TOOL_QUADTAP) -> linux:335 (BTN_TOOL_QUADTAP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:336 (BTN_GEAR_DOWN) -> linux:336 (BTN_GEAR_DOWN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:337 (BTN_GEAR_UP) -> linux:337 (BTN_GEAR_UP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:338 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:339 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:340 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:341 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:342 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:343 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:344 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:345 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:346 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:347 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:348 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:349 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:350 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:351 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:352 (KEY_OK) -> linux:352 (KEY_OK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:353 (KEY_SELECT) -> linux:353 (KEY_SELECT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:354 (KEY_GOTO) -> linux:354 (KEY_GOTO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:355 (KEY_CLEAR) -> linux:355 (KEY_CLEAR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:356 (KEY_POWER2) -> linux:356 (KEY_POWER2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:357 (KEY_OPTION) -> linux:357 (KEY_OPTION) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:358 (KEY_INFO) -> linux:358 (KEY_INFO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:359 (KEY_TIME) -> linux:359 (KEY_TIME) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:360 (KEY_VENDOR) -> linux:360 (KEY_VENDOR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:361 (KEY_ARCHIVE) -> linux:361 (KEY_ARCHIVE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:362 (KEY_PROGRAM) -> linux:362 (KEY_PROGRAM) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:363 (KEY_CHANNEL) -> linux:363 (KEY_CHANNEL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:364 (KEY_FAVORITES) -> linux:364 (KEY_FAVORITES) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:365 (KEY_EPG) -> linux:365 (KEY_EPG) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:366 (KEY_PVR) -> linux:366 (KEY_PVR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:367 (KEY_MHP) -> linux:367 (KEY_MHP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:368 (KEY_LANGUAGE) -> linux:368 (KEY_LANGUAGE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:369 (KEY_TITLE) -> linux:369 (KEY_TITLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:370 (KEY_SUBTITLE) -> linux:370 (KEY_SUBTITLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:371 (KEY_ANGLE) -> linux:371 (KEY_ANGLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:372 (KEY_ZOOM) -> linux:372 (KEY_ZOOM) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:373 (KEY_MODE) -> linux:373 (KEY_MODE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:374 (KEY_KEYBOARD) -> linux:374 (KEY_KEYBOARD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:375 (KEY_SCREEN) -> linux:375 (KEY_SCREEN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:376 (KEY_PC) -> linux:376 (KEY_PC) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:377 (KEY_TV) -> linux:377 (KEY_TV) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:378 (KEY_TV2) -> linux:378 (KEY_TV2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:379 (KEY_VCR) -> linux:379 (KEY_VCR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:380 (KEY_VCR2) -> linux:380 (KEY_VCR2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:381 (KEY_SAT) -> linux:381 (KEY_SAT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:382 (KEY_SAT2) -> linux:382 (KEY_SAT2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:383 (KEY_CD) -> linux:383 (KEY_CD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:384 (KEY_TAPE) -> linux:384 (KEY_TAPE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:385 (KEY_RADIO) -> linux:385 (KEY_RADIO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:386 (KEY_TUNER) -> linux:386 (KEY_TUNER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:387 (KEY_PLAYER) -> linux:387 (KEY_PLAYER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:388 (KEY_TEXT) -> linux:388 (KEY_TEXT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:389 (KEY_DVD) -> linux:389 (KEY_DVD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:390 (KEY_AUX) -> linux:390 (KEY_AUX) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:391 (KEY_MP3) -> linux:391 (KEY_MP3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:392 (KEY_AUDIO) -> linux:392 (KEY_AUDIO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:393 (KEY_VIDEO) -> linux:393 (KEY_VIDEO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:394 (KEY_DIRECTORY) -> linux:394 (KEY_DIRECTORY) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:395 (KEY_LIST) -> linux:395 (KEY_LIST) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:396 (KEY_MEMO) -> linux:396 (KEY_MEMO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:397 (KEY_CALENDAR) -> linux:397 (KEY_CALENDAR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:398 (KEY_RED) -> linux:398 (KEY_RED) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:399 (KEY_GREEN) -> linux:399 (KEY_GREEN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:400 (KEY_YELLOW) -> linux:400 (KEY_YELLOW) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:401 (KEY_BLUE) -> linux:401 (KEY_BLUE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:402 (KEY_CHANNELUP) -> linux:402 (KEY_CHANNELUP) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:403 (KEY_CHANNELDOWN) -> linux:403 (KEY_CHANNELDOWN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:404 (KEY_FIRST) -> linux:404 (KEY_FIRST) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:405 (KEY_LAST) -> linux:405 (KEY_LAST) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:406 (KEY_AB) -> linux:406 (KEY_AB) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:407 (KEY_NEXT) -> linux:407 (KEY_NEXT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:408 (KEY_RESTART) -> linux:408 (KEY_RESTART) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:409 (KEY_SLOW) -> linux:409 (KEY_SLOW) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:410 (KEY_SHUFFLE) -> linux:410 (KEY_SHUFFLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:411 (KEY_BREAK) -> linux:411 (KEY_BREAK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:412 (KEY_PREVIOUS) -> linux:412 (KEY_PREVIOUS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:413 (KEY_DIGITS) -> linux:413 (KEY_DIGITS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:414 (KEY_TEEN) -> linux:414 (KEY_TEEN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:415 (KEY_TWEN) -> linux:415 (KEY_TWEN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:416 (KEY_VIDEOPHONE) -> linux:416 (KEY_VIDEOPHONE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:417 (KEY_GAMES) -> linux:417 (KEY_GAMES) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:418 (KEY_ZOOMIN) -> linux:418 (KEY_ZOOMIN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:419 (KEY_ZOOMOUT) -> linux:419 (KEY_ZOOMOUT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:420 (KEY_ZOOMRESET) -> linux:420 (KEY_ZOOMRESET) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:421 (KEY_WORDPROCESSOR) -> linux:421 (KEY_WORDPROCESSOR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:422 (KEY_EDITOR) -> linux:422 (KEY_EDITOR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:423 (KEY_SPREADSHEET) -> linux:423 (KEY_SPREADSHEET) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:424 (KEY_GRAPHICSEDITOR) -> linux:424 (KEY_GRAPHICSEDITOR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:425 (KEY_PRESENTATION) -> linux:425 (KEY_PRESENTATION) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:426 (KEY_DATABASE) -> linux:426 (KEY_DATABASE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:427 (KEY_NEWS) -> linux:427 (KEY_NEWS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:428 (KEY_VOICEMAIL) -> linux:428 (KEY_VOICEMAIL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:429 (KEY_ADDRESSBOOK) -> linux:429 (KEY_ADDRESSBOOK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:430 (KEY_MESSENGER) -> linux:430 (KEY_MESSENGER) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:431 (KEY_DISPLAYTOGGLE) -> linux:431 (KEY_DISPLAYTOGGLE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:432 (KEY_SPELLCHECK) -> linux:432 (KEY_SPELLCHECK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:433 (KEY_LOGOFF) -> linux:433 (KEY_LOGOFF) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:434 (KEY_DOLLAR) -> linux:434 (KEY_DOLLAR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:435 (KEY_EURO) -> linux:435 (KEY_EURO) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:436 (KEY_FRAMEBACK) -> linux:436 (KEY_FRAMEBACK) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:437 (KEY_FRAMEFORWARD) -> linux:437 (KEY_FRAMEFORWARD) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:438 (KEY_CONTEXT_MENU) -> linux:438 (KEY_CONTEXT_MENU) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:439 (KEY_MEDIA_REPEAT) -> linux:439 (KEY_MEDIA_REPEAT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:440 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:441 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:442 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:443 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:444 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:445 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:446 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:447 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:448 (KEY_DEL_EOL) -> linux:448 (KEY_DEL_EOL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:449 (KEY_DEL_EOS) -> linux:449 (KEY_DEL_EOS) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:450 (KEY_INS_LINE) -> linux:450 (KEY_INS_LINE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:451 (KEY_DEL_LINE) -> linux:451 (KEY_DEL_LINE) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:452 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:453 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:454 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:455 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:456 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:457 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:458 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:459 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:460 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:461 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:462 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:463 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:464 (KEY_FN) -> linux:464 (KEY_FN) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:465 (KEY_FN_ESC) -> linux:465 (KEY_FN_ESC) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:466 (KEY_FN_F1) -> linux:466 (KEY_FN_F1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:467 (KEY_FN_F2) -> linux:467 (KEY_FN_F2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:468 (KEY_FN_F3) -> linux:468 (KEY_FN_F3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:469 (KEY_FN_F4) -> linux:469 (KEY_FN_F4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:470 (KEY_FN_F5) -> linux:470 (KEY_FN_F5) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:471 (KEY_FN_F6) -> linux:471 (KEY_FN_F6) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:472 (KEY_FN_F7) -> linux:472 (KEY_FN_F7) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:473 (KEY_FN_F8) -> linux:473 (KEY_FN_F8) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:474 (KEY_FN_F9) -> linux:474 (KEY_FN_F9) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:475 (KEY_FN_F10) -> linux:475 (KEY_FN_F10) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:476 (KEY_FN_F11) -> linux:476 (KEY_FN_F11) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:477 (KEY_FN_F12) -> linux:477 (KEY_FN_F12) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:478 (KEY_FN_1) -> linux:478 (KEY_FN_1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:479 (KEY_FN_2) -> linux:479 (KEY_FN_2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:480 (KEY_FN_D) -> linux:480 (KEY_FN_D) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:481 (KEY_FN_E) -> linux:481 (KEY_FN_E) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:482 (KEY_FN_F) -> linux:482 (KEY_FN_F) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:483 (KEY_FN_S) -> linux:483 (KEY_FN_S) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:484 (KEY_FN_B) -> linux:484 (KEY_FN_B) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:485 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:486 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:487 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:488 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:489 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:490 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:491 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:492 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:493 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:494 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:495 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:496 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:497 (KEY_BRL_DOT1) -> linux:497 (KEY_BRL_DOT1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:498 (KEY_BRL_DOT2) -> linux:498 (KEY_BRL_DOT2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:499 (KEY_BRL_DOT3) -> linux:499 (KEY_BRL_DOT3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:500 (KEY_BRL_DOT4) -> linux:500 (KEY_BRL_DOT4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:501 (KEY_BRL_DOT5) -> linux:501 (KEY_BRL_DOT5) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:502 (KEY_BRL_DOT6) -> linux:502 (KEY_BRL_DOT6) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:503 (KEY_BRL_DOT7) -> linux:503 (KEY_BRL_DOT7) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:504 (KEY_BRL_DOT8) -> linux:504 (KEY_BRL_DOT8) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:505 (KEY_BRL_DOT9) -> linux:505 (KEY_BRL_DOT9) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:506 (KEY_BRL_DOT10) -> linux:506 (KEY_BRL_DOT10) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:507 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:508 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:509 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:510 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:511 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:512 (KEY_NUMERIC_0) -> linux:512 (KEY_NUMERIC_0) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:513 (KEY_NUMERIC_1) -> linux:513 (KEY_NUMERIC_1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:514 (KEY_NUMERIC_2) -> linux:514 (KEY_NUMERIC_2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:515 (KEY_NUMERIC_3) -> linux:515 (KEY_NUMERIC_3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:516 (KEY_NUMERIC_4) -> linux:516 (KEY_NUMERIC_4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:517 (KEY_NUMERIC_5) -> linux:517 (KEY_NUMERIC_5) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:518 (KEY_NUMERIC_6) -> linux:518 (KEY_NUMERIC_6) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:519 (KEY_NUMERIC_7) -> linux:519 (KEY_NUMERIC_7) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:520 (KEY_NUMERIC_8) -> linux:520 (KEY_NUMERIC_8) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:521 (KEY_NUMERIC_9) -> linux:521 (KEY_NUMERIC_9) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:522 (KEY_NUMERIC_STAR) -> linux:522 (KEY_NUMERIC_STAR) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:523 (KEY_NUMERIC_POUND) -> linux:523 (KEY_NUMERIC_POUND) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* linux:524 (KEY_RFKILL) -> linux:524 (KEY_RFKILL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ -}; -const size_t qemu_input_map_linux_to_qcode_len = sizeof(qemu_input_map_linux_to_qcode) / sizeof(qemu_input_map_linux_to_qcode[0]); diff --git a/pcsx2/USB/qemu-usb/input-keymap-linux-to-qcode.h b/pcsx2/USB/qemu-usb/input-keymap-linux-to-qcode.h deleted file mode 100644 index 818a6529a1..0000000000 --- a/pcsx2/USB/qemu-usb/input-keymap-linux-to-qcode.h +++ /dev/null @@ -1,18 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "hid.h" -extern const QKeyCode qemu_input_map_linux_to_qcode[]; -extern const size_t qemu_input_map_linux_to_qcode_len; diff --git a/pcsx2/USB/qemu-usb/input-keymap-qcode-to-qnum.cpp b/pcsx2/USB/qemu-usb/input-keymap-qcode-to-qnum.cpp index 0cd5cdf476..77121a1b09 100644 --- a/pcsx2/USB/qemu-usb/input-keymap-qcode-to-qnum.cpp +++ b/pcsx2/USB/qemu-usb/input-keymap-qcode-to-qnum.cpp @@ -17,7 +17,7 @@ #include "input-keymap.h" //TODO how much does std::map kill perf if any? -const std::map qemu_input_map_qcode_to_qnum = { +static const std::map qemu_input_map_qcode_to_qnum = { {Q_KEY_CODE_0, 0xb}, /* qcode:Q_KEY_CODE_0 (0) -> linux:11 (KEY_0) -> qnum:11 */ {Q_KEY_CODE_1, 0x2}, /* qcode:Q_KEY_CODE_1 (1) -> linux:2 (KEY_1) -> qnum:2 */ {Q_KEY_CODE_2, 0x3}, /* qcode:Q_KEY_CODE_2 (2) -> linux:3 (KEY_2) -> qnum:3 */ diff --git a/pcsx2/USB/qemu-usb/input-keymap-win32-to-qcode.cpp b/pcsx2/USB/qemu-usb/input-keymap-win32-to-qcode.cpp deleted file mode 100644 index 3bedb6e5f6..0000000000 --- a/pcsx2/USB/qemu-usb/input-keymap-win32-to-qcode.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -/* - * This file is auto-generated from keymaps.csv on 2018-12-22 15:48 - * To re-generate, run: - * keymap-gen --lang=stdc++ --varname=qemu_input_map_win32_to_qcode code-map keymaps.csv win32 qcode -*/ -#include "PrecompiledHeader.h" -#include "input-keymap-win32-to-qcode.h" -const std::array qemu_input_map_win32_to_qcode = { - Q_KEY_CODE_UNMAPPED, /* win32:0 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:1 (VK_LBUTTON) -> linux:256 (BTN_0) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:2 (VK_RBUTTON) -> linux:257 (BTN_1) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:3 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:4 (VK_MBUTTON) -> linux:258 (BTN_2) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:5 (VK_XBUTTON1) -> linux:259 (BTN_3) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:6 (VK_XBUTTON2) -> linux:260 (BTN_4) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:7 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_BACKSPACE, /* win32:8 (VK_BACK) -> linux:14 (KEY_BACKSPACE) -> qcode:Q_KEY_CODE_BACKSPACE (backspace) */ - Q_KEY_CODE_TAB, /* win32:9 (VK_TAB) -> linux:15 (KEY_TAB) -> qcode:Q_KEY_CODE_TAB (tab) */ - Q_KEY_CODE_UNMAPPED, /* win32:10 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:11 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:12 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_RET, /* win32:13 (VK_RETURN) -> linux:28 (KEY_ENTER) -> qcode:Q_KEY_CODE_RET (ret) */ - Q_KEY_CODE_UNMAPPED, /* win32:14 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:15 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_SHIFT, /* win32:16 (VK_LSHIFT) -> linux:42 (KEY_LEFTSHIFT) -> qcode:Q_KEY_CODE_SHIFT (shift) */ - Q_KEY_CODE_CTRL, /* win32:17 (VK_CONTROL) -> linux:29 (KEY_LEFTCTRL) -> qcode:Q_KEY_CODE_CTRL (ctrl) */ - Q_KEY_CODE_ALT, /* win32:18 (VK_MENU) -> linux:56 (KEY_LEFTALT) -> qcode:Q_KEY_CODE_ALT (alt) */ - Q_KEY_CODE_PAUSE, /* win32:19 (VK_PAUSE) -> linux:119 (KEY_PAUSE) -> qcode:Q_KEY_CODE_PAUSE (pause) */ - Q_KEY_CODE_CAPS_LOCK, /* win32:20 (VK_CAPITAL) -> linux:58 (KEY_CAPSLOCK) -> qcode:Q_KEY_CODE_CAPS_LOCK (caps_lock) */ - Q_KEY_CODE_UNMAPPED, /* win32:21 (VK_HANGEUL) -> linux:122 (KEY_HANGEUL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:22 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:23 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:24 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:25 (VK_HANJA) -> linux:123 (KEY_HANJA) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:26 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_ESC, /* win32:27 (VK_ESCAPE) -> linux:1 (KEY_ESC) -> qcode:Q_KEY_CODE_ESC (esc) */ - Q_KEY_CODE_UNMAPPED, /* win32:28 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:29 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:30 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:31 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_SPC, /* win32:32 (VK_SPACE) -> linux:57 (KEY_SPACE) -> qcode:Q_KEY_CODE_SPC (spc) */ - Q_KEY_CODE_PGUP, /* win32:33 (VK_PRIOR) -> linux:104 (KEY_PAGEUP) -> qcode:Q_KEY_CODE_PGUP (pgup) */ - Q_KEY_CODE_PGDN, /* win32:34 (VK_NEXT) -> linux:109 (KEY_PAGEDOWN) -> qcode:Q_KEY_CODE_PGDN (pgdn) */ - Q_KEY_CODE_END, /* win32:35 (VK_END) -> linux:107 (KEY_END) -> qcode:Q_KEY_CODE_END (end) */ - Q_KEY_CODE_HOME, /* win32:36 (VK_HOME) -> linux:102 (KEY_HOME) -> qcode:Q_KEY_CODE_HOME (home) */ - Q_KEY_CODE_LEFT, /* win32:37 (VK_LEFT) -> linux:105 (KEY_LEFT) -> qcode:Q_KEY_CODE_LEFT (left) */ - Q_KEY_CODE_UP, /* win32:38 (VK_UP) -> linux:103 (KEY_UP) -> qcode:Q_KEY_CODE_UP (up) */ - Q_KEY_CODE_RIGHT, /* win32:39 (VK_RIGHT) -> linux:106 (KEY_RIGHT) -> qcode:Q_KEY_CODE_RIGHT (right) */ - Q_KEY_CODE_DOWN, /* win32:40 (VK_DOWN) -> linux:108 (KEY_DOWN) -> qcode:Q_KEY_CODE_DOWN (down) */ - Q_KEY_CODE_UNMAPPED, /* win32:41 (VK_SELECT) -> linux:353 (KEY_SELECT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:42 (VK_PRINT) -> linux:210 (KEY_PRINT) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:43 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_SYSRQ, /* win32:44 (VK_SNAPSHOT) -> linux:99 (KEY_SYSRQ) -> qcode:Q_KEY_CODE_SYSRQ (sysrq) */ - Q_KEY_CODE_INSERT, /* win32:45 (VK_INSERT) -> linux:110 (KEY_INSERT) -> qcode:Q_KEY_CODE_INSERT (insert) */ - Q_KEY_CODE_DELETE, /* win32:46 (VK_DELETE) -> linux:111 (KEY_DELETE) -> qcode:Q_KEY_CODE_DELETE (delete) */ - Q_KEY_CODE_HELP, /* win32:47 (VK_HELP) -> linux:138 (KEY_HELP) -> qcode:Q_KEY_CODE_HELP (help) */ - Q_KEY_CODE_0, /* win32:48 (VK_0) -> linux:11 (KEY_0) -> qcode:Q_KEY_CODE_0 (0) */ - Q_KEY_CODE_1, /* win32:49 (VK_1) -> linux:2 (KEY_1) -> qcode:Q_KEY_CODE_1 (1) */ - Q_KEY_CODE_2, /* win32:50 (VK_2) -> linux:3 (KEY_2) -> qcode:Q_KEY_CODE_2 (2) */ - Q_KEY_CODE_3, /* win32:51 (VK_3) -> linux:4 (KEY_3) -> qcode:Q_KEY_CODE_3 (3) */ - Q_KEY_CODE_4, /* win32:52 (VK_4) -> linux:5 (KEY_4) -> qcode:Q_KEY_CODE_4 (4) */ - Q_KEY_CODE_5, /* win32:53 (VK_5) -> linux:6 (KEY_5) -> qcode:Q_KEY_CODE_5 (5) */ - Q_KEY_CODE_6, /* win32:54 (VK_6) -> linux:7 (KEY_6) -> qcode:Q_KEY_CODE_6 (6) */ - Q_KEY_CODE_7, /* win32:55 (VK_7) -> linux:8 (KEY_7) -> qcode:Q_KEY_CODE_7 (7) */ - Q_KEY_CODE_8, /* win32:56 (VK_8) -> linux:9 (KEY_8) -> qcode:Q_KEY_CODE_8 (8) */ - Q_KEY_CODE_9, /* win32:57 (VK_9) -> linux:10 (KEY_9) -> qcode:Q_KEY_CODE_9 (9) */ - Q_KEY_CODE_UNMAPPED, /* win32:58 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:59 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:60 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:61 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:62 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:63 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:64 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_A, /* win32:65 (VK_A) -> linux:30 (KEY_A) -> qcode:Q_KEY_CODE_A (a) */ - Q_KEY_CODE_B, /* win32:66 (VK_B) -> linux:48 (KEY_B) -> qcode:Q_KEY_CODE_B (b) */ - Q_KEY_CODE_C, /* win32:67 (VK_C) -> linux:46 (KEY_C) -> qcode:Q_KEY_CODE_C (c) */ - Q_KEY_CODE_D, /* win32:68 (VK_D) -> linux:32 (KEY_D) -> qcode:Q_KEY_CODE_D (d) */ - Q_KEY_CODE_E, /* win32:69 (VK_E) -> linux:18 (KEY_E) -> qcode:Q_KEY_CODE_E (e) */ - Q_KEY_CODE_F, /* win32:70 (VK_F) -> linux:33 (KEY_F) -> qcode:Q_KEY_CODE_F (f) */ - Q_KEY_CODE_G, /* win32:71 (VK_G) -> linux:34 (KEY_G) -> qcode:Q_KEY_CODE_G (g) */ - Q_KEY_CODE_H, /* win32:72 (VK_H) -> linux:35 (KEY_H) -> qcode:Q_KEY_CODE_H (h) */ - Q_KEY_CODE_I, /* win32:73 (VK_I) -> linux:23 (KEY_I) -> qcode:Q_KEY_CODE_I (i) */ - Q_KEY_CODE_J, /* win32:74 (VK_J) -> linux:36 (KEY_J) -> qcode:Q_KEY_CODE_J (j) */ - Q_KEY_CODE_K, /* win32:75 (VK_K) -> linux:37 (KEY_K) -> qcode:Q_KEY_CODE_K (k) */ - Q_KEY_CODE_L, /* win32:76 (VK_L) -> linux:38 (KEY_L) -> qcode:Q_KEY_CODE_L (l) */ - Q_KEY_CODE_M, /* win32:77 (VK_M) -> linux:50 (KEY_M) -> qcode:Q_KEY_CODE_M (m) */ - Q_KEY_CODE_N, /* win32:78 (VK_N) -> linux:49 (KEY_N) -> qcode:Q_KEY_CODE_N (n) */ - Q_KEY_CODE_O, /* win32:79 (VK_O) -> linux:24 (KEY_O) -> qcode:Q_KEY_CODE_O (o) */ - Q_KEY_CODE_P, /* win32:80 (VK_P) -> linux:25 (KEY_P) -> qcode:Q_KEY_CODE_P (p) */ - Q_KEY_CODE_Q, /* win32:81 (VK_Q) -> linux:16 (KEY_Q) -> qcode:Q_KEY_CODE_Q (q) */ - Q_KEY_CODE_R, /* win32:82 (VK_R) -> linux:19 (KEY_R) -> qcode:Q_KEY_CODE_R (r) */ - Q_KEY_CODE_S, /* win32:83 (VK_S) -> linux:31 (KEY_S) -> qcode:Q_KEY_CODE_S (s) */ - Q_KEY_CODE_T, /* win32:84 (VK_T) -> linux:20 (KEY_T) -> qcode:Q_KEY_CODE_T (t) */ - Q_KEY_CODE_U, /* win32:85 (VK_U) -> linux:22 (KEY_U) -> qcode:Q_KEY_CODE_U (u) */ - Q_KEY_CODE_V, /* win32:86 (VK_V) -> linux:47 (KEY_V) -> qcode:Q_KEY_CODE_V (v) */ - Q_KEY_CODE_W, /* win32:87 (VK_W) -> linux:17 (KEY_W) -> qcode:Q_KEY_CODE_W (w) */ - Q_KEY_CODE_X, /* win32:88 (VK_X) -> linux:45 (KEY_X) -> qcode:Q_KEY_CODE_X (x) */ - Q_KEY_CODE_Y, /* win32:89 (VK_Y) -> linux:21 (KEY_Y) -> qcode:Q_KEY_CODE_Y (y) */ - Q_KEY_CODE_Z, /* win32:90 (VK_Z) -> linux:44 (KEY_Z) -> qcode:Q_KEY_CODE_Z (z) */ - Q_KEY_CODE_META_L, /* win32:91 (VK_LWIN) -> linux:125 (KEY_LEFTMETA) -> qcode:Q_KEY_CODE_META_L (meta_l) */ - Q_KEY_CODE_META_R, /* win32:92 (VK_RWIN) -> linux:126 (KEY_RIGHTMETA) -> qcode:Q_KEY_CODE_META_R (meta_r) */ - Q_KEY_CODE_COMPOSE, /* win32:93 (VK_APPS) -> linux:127 (KEY_COMPOSE) -> qcode:Q_KEY_CODE_COMPOSE (compose) */ - Q_KEY_CODE_UNMAPPED, /* win32:94 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_SLEEP, /* win32:95 (VK_SLEEP) -> linux:142 (KEY_SLEEP) -> qcode:Q_KEY_CODE_SLEEP (sleep) */ - Q_KEY_CODE_KP_0, /* win32:96 (VK_NUMPAD0) -> linux:82 (KEY_KP0) -> qcode:Q_KEY_CODE_KP_0 (kp_0) */ - Q_KEY_CODE_KP_1, /* win32:97 (VK_NUMPAD1) -> linux:79 (KEY_KP1) -> qcode:Q_KEY_CODE_KP_1 (kp_1) */ - Q_KEY_CODE_KP_2, /* win32:98 (VK_NUMPAD2) -> linux:80 (KEY_KP2) -> qcode:Q_KEY_CODE_KP_2 (kp_2) */ - Q_KEY_CODE_KP_3, /* win32:99 (VK_NUMPAD3) -> linux:81 (KEY_KP3) -> qcode:Q_KEY_CODE_KP_3 (kp_3) */ - Q_KEY_CODE_KP_4, /* win32:100 (VK_NUMPAD4) -> linux:75 (KEY_KP4) -> qcode:Q_KEY_CODE_KP_4 (kp_4) */ - Q_KEY_CODE_KP_5, /* win32:101 (VK_NUMPAD5) -> linux:76 (KEY_KP5) -> qcode:Q_KEY_CODE_KP_5 (kp_5) */ - Q_KEY_CODE_KP_6, /* win32:102 (VK_NUMPAD6) -> linux:77 (KEY_KP6) -> qcode:Q_KEY_CODE_KP_6 (kp_6) */ - Q_KEY_CODE_KP_7, /* win32:103 (VK_NUMPAD7) -> linux:71 (KEY_KP7) -> qcode:Q_KEY_CODE_KP_7 (kp_7) */ - Q_KEY_CODE_KP_8, /* win32:104 (VK_NUMPAD8) -> linux:72 (KEY_KP8) -> qcode:Q_KEY_CODE_KP_8 (kp_8) */ - Q_KEY_CODE_KP_9, /* win32:105 (VK_NUMPAD9) -> linux:73 (KEY_KP9) -> qcode:Q_KEY_CODE_KP_9 (kp_9) */ - Q_KEY_CODE_KP_MULTIPLY, /* win32:106 (VK_MULTIPLY) -> linux:55 (KEY_KPASTERISK) -> qcode:Q_KEY_CODE_KP_MULTIPLY (kp_multiply) */ - Q_KEY_CODE_KP_ADD, /* win32:107 (VK_ADD) -> linux:78 (KEY_KPPLUS) -> qcode:Q_KEY_CODE_KP_ADD (kp_add) */ - Q_KEY_CODE_KP_COMMA, /* win32:108 (VK_SEPARATOR??) -> linux:121 (KEY_KPCOMMA) -> qcode:Q_KEY_CODE_KP_COMMA (kp_comma) */ - Q_KEY_CODE_KP_SUBTRACT, /* win32:109 (VK_SUBTRACT) -> linux:74 (KEY_KPMINUS) -> qcode:Q_KEY_CODE_KP_SUBTRACT (kp_subtract) */ - Q_KEY_CODE_KP_DECIMAL, /* win32:110 (VK_DECIMAL) -> linux:83 (KEY_KPDOT) -> qcode:Q_KEY_CODE_KP_DECIMAL (kp_decimal) */ - Q_KEY_CODE_KP_DIVIDE, /* win32:111 (VK_DIVIDE) -> linux:98 (KEY_KPSLASH) -> qcode:Q_KEY_CODE_KP_DIVIDE (kp_divide) */ - Q_KEY_CODE_F1, /* win32:112 (VK_F1) -> linux:59 (KEY_F1) -> qcode:Q_KEY_CODE_F1 (f1) */ - Q_KEY_CODE_F2, /* win32:113 (VK_F2) -> linux:60 (KEY_F2) -> qcode:Q_KEY_CODE_F2 (f2) */ - Q_KEY_CODE_F3, /* win32:114 (VK_F3) -> linux:61 (KEY_F3) -> qcode:Q_KEY_CODE_F3 (f3) */ - Q_KEY_CODE_F4, /* win32:115 (VK_F4) -> linux:62 (KEY_F4) -> qcode:Q_KEY_CODE_F4 (f4) */ - Q_KEY_CODE_F5, /* win32:116 (VK_F5) -> linux:63 (KEY_F5) -> qcode:Q_KEY_CODE_F5 (f5) */ - Q_KEY_CODE_F6, /* win32:117 (VK_F6) -> linux:64 (KEY_F6) -> qcode:Q_KEY_CODE_F6 (f6) */ - Q_KEY_CODE_F7, /* win32:118 (VK_F7) -> linux:65 (KEY_F7) -> qcode:Q_KEY_CODE_F7 (f7) */ - Q_KEY_CODE_F8, /* win32:119 (VK_F8) -> linux:66 (KEY_F8) -> qcode:Q_KEY_CODE_F8 (f8) */ - Q_KEY_CODE_F9, /* win32:120 (VK_F9) -> linux:67 (KEY_F9) -> qcode:Q_KEY_CODE_F9 (f9) */ - Q_KEY_CODE_F10, /* win32:121 (VK_F10) -> linux:68 (KEY_F10) -> qcode:Q_KEY_CODE_F10 (f10) */ - Q_KEY_CODE_F11, /* win32:122 (VK_F11) -> linux:87 (KEY_F11) -> qcode:Q_KEY_CODE_F11 (f11) */ - Q_KEY_CODE_F12, /* win32:123 (VK_F12) -> linux:88 (KEY_F12) -> qcode:Q_KEY_CODE_F12 (f12) */ - Q_KEY_CODE_UNMAPPED, /* win32:124 (VK_F13) -> linux:183 (KEY_F13) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:125 (VK_F14) -> linux:184 (KEY_F14) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:126 (VK_F15) -> linux:185 (KEY_F15) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:127 (VK_F16) -> linux:186 (KEY_F16) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:128 (VK_F17) -> linux:187 (KEY_F17) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:129 (VK_F18) -> linux:188 (KEY_F18) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:130 (VK_F19) -> linux:189 (KEY_F19) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:131 (VK_F20) -> linux:190 (KEY_F20) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:132 (VK_F21) -> linux:191 (KEY_F21) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:133 (VK_F22) -> linux:192 (KEY_F22) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:134 (VK_F23) -> linux:193 (KEY_F23) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:135 (VK_F24) -> linux:194 (KEY_F24) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:136 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:137 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:138 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:139 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:140 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:141 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:142 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:143 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_NUM_LOCK, /* win32:144 (VK_NUMLOCK) -> linux:69 (KEY_NUMLOCK) -> qcode:Q_KEY_CODE_NUM_LOCK (num_lock) */ - Q_KEY_CODE_SCROLL_LOCK, /* win32:145 (VK_SCROLL) -> linux:70 (KEY_SCROLLLOCK) -> qcode:Q_KEY_CODE_SCROLL_LOCK (scroll_lock) */ - Q_KEY_CODE_UNMAPPED, /* win32:146 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:147 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:148 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:149 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:150 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:151 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:152 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:153 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:154 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:155 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:156 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:157 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:158 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:159 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_SHIFT, /* win32:160 (VK_LSHIFT) -> linux:42 (KEY_LEFTSHIFT) -> qcode:Q_KEY_CODE_SHIFT (shift) */ - Q_KEY_CODE_SHIFT_R, /* win32:161 (VK_RSHIFT) -> linux:54 (KEY_RIGHTSHIFT) -> qcode:Q_KEY_CODE_SHIFT_R (shift_r) */ - Q_KEY_CODE_CTRL, /* win32:162 (VK_CONTROL) -> linux:29 (KEY_LEFTCTRL) -> qcode:Q_KEY_CODE_CTRL (ctrl) */ - Q_KEY_CODE_CTRL_R, /* win32:163 (VK_RCONTROL) -> linux:97 (KEY_RIGHTCTRL) -> qcode:Q_KEY_CODE_CTRL_R (ctrl_r) */ - Q_KEY_CODE_ALT, /* win32:164 (VK_MENU) -> linux:56 (KEY_LEFTALT) -> qcode:Q_KEY_CODE_ALT (alt) */ - Q_KEY_CODE_ALT_R, /* win32:165 (VK_RMENU) -> linux:100 (KEY_RIGHTALT) -> qcode:Q_KEY_CODE_ALT_R (alt_r) */ - Q_KEY_CODE_AC_BACK, /* win32:166 (VK_BROWSER_BACK) -> linux:158 (KEY_BACK) -> qcode:Q_KEY_CODE_AC_BACK (ac_back) */ - Q_KEY_CODE_AC_FORWARD, /* win32:167 (VK_BROWSER_FORWARD) -> linux:159 (KEY_FORWARD) -> qcode:Q_KEY_CODE_AC_FORWARD (ac_forward) */ - Q_KEY_CODE_AC_REFRESH, /* win32:168 (VK_BROWSER_REFRESH) -> linux:173 (KEY_REFRESH) -> qcode:Q_KEY_CODE_AC_REFRESH (ac_refresh) */ - Q_KEY_CODE_STOP, /* win32:169 (VK_BROWSER_STOP) -> linux:128 (KEY_STOP) -> qcode:Q_KEY_CODE_STOP (stop) */ - Q_KEY_CODE_UNMAPPED, /* win32:170 (VK_BROWSER_SEARCH) -> linux:217 (KEY_SEARCH) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:171 (VK_BROWSER_FAVOURITES) -> linux:364 (KEY_FAVORITES) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_AC_HOME, /* win32:172 (VK_BROWSER_HOME) -> linux:172 (KEY_HOMEPAGE) -> qcode:Q_KEY_CODE_AC_HOME (ac_home) */ - Q_KEY_CODE_AUDIOMUTE, /* win32:173 (VK_VOLUME_MUTE) -> linux:113 (KEY_MUTE) -> qcode:Q_KEY_CODE_AUDIOMUTE (audiomute) */ - Q_KEY_CODE_VOLUMEDOWN, /* win32:174 (VK_VOLUME_DOWN) -> linux:114 (KEY_VOLUMEDOWN) -> qcode:Q_KEY_CODE_VOLUMEDOWN (volumedown) */ - Q_KEY_CODE_VOLUMEUP, /* win32:175 (VK_VOLUME_UP) -> linux:115 (KEY_VOLUMEUP) -> qcode:Q_KEY_CODE_VOLUMEUP (volumeup) */ - Q_KEY_CODE_AUDIONEXT, /* win32:176 (VK_MEDIA_NEXT_TRACK) -> linux:163 (KEY_NEXTSONG) -> qcode:Q_KEY_CODE_AUDIONEXT (audionext) */ - Q_KEY_CODE_AUDIOPREV, /* win32:177 (VK_MEDIA_PREV_TRACK) -> linux:165 (KEY_PREVIOUSSONG) -> qcode:Q_KEY_CODE_AUDIOPREV (audioprev) */ - Q_KEY_CODE_AUDIOSTOP, /* win32:178 (VK_MEDIA_STOP) -> linux:166 (KEY_STOPCD) -> qcode:Q_KEY_CODE_AUDIOSTOP (audiostop) */ - Q_KEY_CODE_AUDIOPLAY, /* win32:179 (VK_MEDIA_PLAY_PAUSE) -> linux:164 (KEY_PLAYPAUSE) -> qcode:Q_KEY_CODE_AUDIOPLAY (audioplay) */ - Q_KEY_CODE_UNMAPPED, /* win32:180 (VK_LAUNCH_MAIL) -> linux:215 (KEY_EMAIL) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:181 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:182 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:183 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:184 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:185 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_SEMICOLON, /* win32:186 (VK_OEM_1) -> linux:39 (KEY_SEMICOLON) -> qcode:Q_KEY_CODE_SEMICOLON (semicolon) */ - Q_KEY_CODE_EQUAL, /* win32:187 (VK_OEM_PLUS) -> linux:13 (KEY_EQUAL) -> qcode:Q_KEY_CODE_EQUAL (equal) */ - Q_KEY_CODE_COMMA, /* win32:188 (VK_OEM_COMMA) -> linux:51 (KEY_COMMA) -> qcode:Q_KEY_CODE_COMMA (comma) */ - Q_KEY_CODE_MINUS, /* win32:189 (VK_OEM_MINUS) -> linux:12 (KEY_MINUS) -> qcode:Q_KEY_CODE_MINUS (minus) */ - Q_KEY_CODE_DOT, /* win32:190 (VK_OEM_PERIOD) -> linux:52 (KEY_DOT) -> qcode:Q_KEY_CODE_DOT (dot) */ - Q_KEY_CODE_SLASH, /* win32:191 (VK_OEM_2) -> linux:53 (KEY_SLASH) -> qcode:Q_KEY_CODE_SLASH (slash) */ - Q_KEY_CODE_GRAVE_ACCENT, /* win32:192 (VK_OEM_3) -> linux:41 (KEY_GRAVE) -> qcode:Q_KEY_CODE_GRAVE_ACCENT (grave_accent) */ - Q_KEY_CODE_UNMAPPED, /* win32:193 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:194 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:195 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:196 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:197 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:198 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:199 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:200 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:201 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:202 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:203 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:204 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:205 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:206 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:207 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:208 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:209 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:210 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:211 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:212 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:213 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:214 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:215 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:216 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:217 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:218 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_BRACKET_LEFT, /* win32:219 (VK_OEM_4) -> linux:26 (KEY_LEFTBRACE) -> qcode:Q_KEY_CODE_BRACKET_LEFT (bracket_left) */ - Q_KEY_CODE_BACKSLASH, /* win32:220 (VK_OEM_5) -> linux:43 (KEY_BACKSLASH) -> qcode:Q_KEY_CODE_BACKSLASH (backslash) */ - Q_KEY_CODE_BRACKET_RIGHT, /* win32:221 (VK_OEM_6) -> linux:27 (KEY_RIGHTBRACE) -> qcode:Q_KEY_CODE_BRACKET_RIGHT (bracket_right) */ - Q_KEY_CODE_APOSTROPHE, /* win32:222 (VK_OEM_7) -> linux:40 (KEY_APOSTROPHE) -> qcode:Q_KEY_CODE_APOSTROPHE (apostrophe) */ - Q_KEY_CODE_UNMAPPED, /* win32:223 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:224 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_LESS, /* win32:225 (VK_OEM_102) -> linux:86 (KEY_102ND) -> qcode:Q_KEY_CODE_LESS (less) */ - Q_KEY_CODE_UNMAPPED, /* win32:226 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:227 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:228 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:229 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:230 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:231 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:232 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:233 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:234 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:235 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:236 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:237 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:238 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:239 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:240 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:241 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:242 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:243 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:244 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:245 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:246 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:247 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:248 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:249 (unnamed) -> linux:None (unnamed) -> qcode:None (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:250 (VK_PLAY) -> linux:207 (KEY_PLAY) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ - Q_KEY_CODE_UNMAPPED, /* win32:251 (VK_ZOOM) -> linux:372 (KEY_ZOOM) -> qcode:Q_KEY_CODE_UNMAPPED (unnamed) */ -}; diff --git a/pcsx2/USB/qemu-usb/input-keymap-win32-to-qcode.h b/pcsx2/USB/qemu-usb/input-keymap-win32-to-qcode.h deleted file mode 100644 index 024661b1df..0000000000 --- a/pcsx2/USB/qemu-usb/input-keymap-win32-to-qcode.h +++ /dev/null @@ -1,24 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -/* - * This file is auto-generated from keymaps.csv on 2018-12-22 15:48 - * Database checksum sha256(ef8f29f4e4294479e2789aa61e410c4b0464d4f0ad16bcc1526086a4f123bc10) - * To re-generate, run: - * keymap-gen --lang=stdc++ --varname=qemu_input_map_win32_to_qcode code-map keymaps.csv win32 qcode -*/ -#include -#include "hid.h" -extern const std::array qemu_input_map_win32_to_qcode; diff --git a/pcsx2/USB/qemu-usb/input-keymap.h b/pcsx2/USB/qemu-usb/input-keymap.h index b8f065df8d..0287e64ab6 100644 --- a/pcsx2/USB/qemu-usb/input-keymap.h +++ b/pcsx2/USB/qemu-usb/input-keymap.h @@ -13,10 +13,8 @@ * If not, see . */ -#include #include "hid.h" -extern const std::map qemu_input_map_qcode_to_qnum; int qemu_input_qcode_to_number(const QKeyCode value); int qemu_input_key_value_to_number(const KeyValue* value); int qemu_input_key_value_to_scancode(const KeyValue* value, bool down, int* codes); diff --git a/pcsx2/USB/qemu-usb/iov.cpp b/pcsx2/USB/qemu-usb/iov.cpp index ad428f557c..47a8b66523 100644 --- a/pcsx2/USB/qemu-usb/iov.cpp +++ b/pcsx2/USB/qemu-usb/iov.cpp @@ -17,15 +17,14 @@ */ #include "PrecompiledHeader.h" -#include "vl.h" -//#include "qemu-common.h" -#include "iov.h" -#include "glib.h" -//#include "qemu/sockets.h" -//#include "qemu/cutils.h" +#include "USB/qemu-usb/iov.h" +#include #include +#include -size_t iov_from_buf_full(const struct iovec* iov, unsigned int iov_cnt, + // TODO(Stenzek): Rewrite this stuff to LGPL. + +size_t iov_from_buf(const struct usb_iovec* iov, unsigned int iov_cnt, size_t offset, const void* buf, size_t bytes) { size_t done; @@ -34,7 +33,7 @@ size_t iov_from_buf_full(const struct iovec* iov, unsigned int iov_cnt, { if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); + size_t len = std::min(iov[i].iov_len - offset, bytes - done); memcpy((char*)iov[i].iov_base + offset, (char*)buf + done, len); done += len; offset = 0; @@ -48,7 +47,7 @@ size_t iov_from_buf_full(const struct iovec* iov, unsigned int iov_cnt, return done; } -size_t iov_to_buf_full(const struct iovec* iov, const unsigned int iov_cnt, +size_t iov_to_buf(const struct usb_iovec* iov, const unsigned int iov_cnt, size_t offset, void* buf, size_t bytes) { size_t done; @@ -57,7 +56,7 @@ size_t iov_to_buf_full(const struct iovec* iov, const unsigned int iov_cnt, { if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); + size_t len = std::min(iov[i].iov_len - offset, bytes - done); memcpy((char*)buf + done, (char*)iov[i].iov_base + offset, len); done += len; offset = 0; @@ -71,7 +70,7 @@ size_t iov_to_buf_full(const struct iovec* iov, const unsigned int iov_cnt, return done; } -size_t iov_memset(const struct iovec* iov, const unsigned int iov_cnt, +size_t iov_memset(const struct usb_iovec* iov, const unsigned int iov_cnt, size_t offset, int fillc, size_t bytes) { size_t done; @@ -80,7 +79,7 @@ size_t iov_memset(const struct iovec* iov, const unsigned int iov_cnt, { if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); + size_t len = std::min(iov[i].iov_len - offset, bytes - done); memset((char*)iov[i].iov_base + offset, fillc, len); done += len; offset = 0; @@ -94,67 +93,17 @@ size_t iov_memset(const struct iovec* iov, const unsigned int iov_cnt, return done; } -size_t iov_size(const struct iovec* iov, const unsigned int iov_cnt) -{ - size_t len; - unsigned int i; - - len = 0; - for (i = 0; i < iov_cnt; i++) - { - len += iov[i].iov_len; - } - return len; -} - -unsigned iov_copy(struct iovec* dst_iov, unsigned int dst_iov_cnt, - const struct iovec* iov, unsigned int iov_cnt, - size_t offset, size_t bytes) -{ - size_t len; - unsigned int i, j; - for (i = 0, j = 0; - i < iov_cnt && j < dst_iov_cnt && (offset || bytes); i++) - { - if (offset >= iov[i].iov_len) - { - offset -= iov[i].iov_len; - continue; - } - len = MIN(bytes, iov[i].iov_len - offset); - - dst_iov[j].iov_base = (char*)iov[i].iov_base + offset; - dst_iov[j].iov_len = len; - j++; - bytes -= len; - offset = 0; - } - assert(offset == 0); - return j; -} /* io vectors */ -void qemu_iovec_init(QEMUIOVector* qiov, int alloc_hint) +void qemu_iovec_init(QEMUIOVector* qiov) { - qiov->iov = my_g_new(struct iovec, alloc_hint); + qiov->iov = (struct usb_iovec*)std::malloc(sizeof(usb_iovec)); qiov->niov = 0; - qiov->nalloc = alloc_hint; + qiov->nalloc = 1; qiov->size = 0; } -void qemu_iovec_init_external(QEMUIOVector* qiov, struct iovec* iov, int niov) -{ - int i; - - qiov->iov = iov; - qiov->niov = niov; - qiov->nalloc = -1; - qiov->size = 0; - for (i = 0; i < niov; i++) - qiov->size += iov[i].iov_len; -} - void qemu_iovec_add(QEMUIOVector* qiov, void* base, size_t len) { assert(qiov->nalloc != -1); @@ -162,7 +111,7 @@ void qemu_iovec_add(QEMUIOVector* qiov, void* base, size_t len) if (qiov->niov == qiov->nalloc) { qiov->nalloc = 2 * qiov->nalloc + 1; - qiov->iov = my_g_renew(struct iovec, qiov->iov, qiov->nalloc); + qiov->iov = (struct usb_iovec*)std::realloc(qiov->iov, sizeof(usb_iovec) * qiov->nalloc); } qiov->iov[qiov->niov].iov_base = base; qiov->iov[qiov->niov].iov_len = len; @@ -170,90 +119,12 @@ void qemu_iovec_add(QEMUIOVector* qiov, void* base, size_t len) ++qiov->niov; } -/* - * Concatenates (partial) iovecs from src_iov to the end of dst. - * It starts copying after skipping `soffset' bytes at the - * beginning of src and adds individual vectors from src to - * dst copies up to `sbytes' bytes total, or up to the end - * of src_iov if it comes first. This way, it is okay to specify - * very large value for `sbytes' to indicate "up to the end - * of src". - * Only vector pointers are processed, not the actual data buffers. - */ -size_t qemu_iovec_concat_iov(QEMUIOVector* dst, - struct iovec* src_iov, unsigned int src_cnt, - size_t soffset, size_t sbytes) -{ - unsigned int i; - size_t done; - - if (!sbytes) - { - return 0; - } - assert(dst->nalloc != -1); - for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) - { - if (soffset < src_iov[i].iov_len) - { - size_t len = MIN(src_iov[i].iov_len - soffset, sbytes - done); - qemu_iovec_add(dst, (char*)src_iov[i].iov_base + soffset, len); - done += len; - soffset = 0; - } - else - { - soffset -= src_iov[i].iov_len; - } - } - assert(soffset == 0); /* offset beyond end of src */ - - return done; -} - -/* - * Concatenates (partial) iovecs from src to the end of dst. - * It starts copying after skipping `soffset' bytes at the - * beginning of src and adds individual vectors from src to - * dst copies up to `sbytes' bytes total, or up to the end - * of src if it comes first. This way, it is okay to specify - * very large value for `sbytes' to indicate "up to the end - * of src". - * Only vector pointers are processed, not the actual data buffers. - */ -void qemu_iovec_concat(QEMUIOVector* dst, - QEMUIOVector* src, size_t soffset, size_t sbytes) -{ - qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes); -} - -/* - * Check if the contents of the iovecs are all zero - */ -/*bool qemu_iovec_is_zero(QEMUIOVector *qiov) -{ - int i; - for (i = 0; i < qiov->niov; i++) { - size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long)); - uint8_t *ptr = (uint8_t *)qiov->iov[i].iov_base; - if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) { - return false; - } - for (; offs < qiov->iov[i].iov_len; offs++) { - if (ptr[offs]) { - return false; - } - } - } - return true; -}*/ - void qemu_iovec_destroy(QEMUIOVector* qiov) { assert(qiov->nalloc != -1); qemu_iovec_reset(qiov); - my_g_free(qiov->iov); + std::free(qiov->iov); qiov->nalloc = 0; qiov->iov = NULL; } @@ -265,161 +136,3 @@ void qemu_iovec_reset(QEMUIOVector* qiov) qiov->niov = 0; qiov->size = 0; } - -size_t qemu_iovec_to_buf(QEMUIOVector* qiov, size_t offset, - void* buf, size_t bytes) -{ - return iov_to_buf(qiov->iov, qiov->niov, offset, buf, bytes); -} - -size_t qemu_iovec_from_buf(QEMUIOVector* qiov, size_t offset, - const void* buf, size_t bytes) -{ - return iov_from_buf(qiov->iov, qiov->niov, offset, buf, bytes); -} - -size_t qemu_iovec_memset(QEMUIOVector* qiov, size_t offset, - int fillc, size_t bytes) -{ - return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes); -} - -/** - * Check that I/O vector contents are identical - * - * The IO vectors must have the same structure (same length of all parts). - * A typical usage is to compare vectors created with qemu_iovec_clone(). - * - * @a: I/O vector - * @b: I/O vector - * @ret: Offset to first mismatching byte or -1 if match - */ -ssize_t qemu_iovec_compare(QEMUIOVector* a, QEMUIOVector* b) -{ - int i; - ssize_t offset = 0; - - assert(a->niov == b->niov); - for (i = 0; i < a->niov; i++) - { - size_t len = 0; - uint8_t* p = (uint8_t*)a->iov[i].iov_base; - uint8_t* q = (uint8_t*)b->iov[i].iov_base; - - assert(a->iov[i].iov_len == b->iov[i].iov_len); - while (len < a->iov[i].iov_len && *p++ == *q++) - { - len++; - } - - offset += len; - - if (len != a->iov[i].iov_len) - { - return offset; - } - } - return -1; -} - -typedef struct -{ - int src_index; - struct iovec* src_iov; - void* dest_base; -} IOVectorSortElem; - -static int sortelem_cmp_src_base(const void* a, const void* b) -{ - const IOVectorSortElem* elem_a = (const IOVectorSortElem*)a; - const IOVectorSortElem* elem_b = (const IOVectorSortElem*)b; - - /* Don't overflow */ - if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) - { - return -1; - } - else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) - { - return 1; - } - else - { - return 0; - } -} - -static int sortelem_cmp_src_index(const void* a, const void* b) -{ - const IOVectorSortElem* elem_a = (const IOVectorSortElem*)a; - const IOVectorSortElem* elem_b = (const IOVectorSortElem*)b; - - return elem_a->src_index - elem_b->src_index; -} - -size_t iov_discard_front(struct iovec** iov, unsigned int* iov_cnt, - size_t bytes) -{ - size_t total = 0; - struct iovec* cur; - - for (cur = *iov; *iov_cnt > 0; cur++) - { - if (cur->iov_len > bytes) - { - cur->iov_base = (uint8_t*)cur->iov_base + bytes; - cur->iov_len -= bytes; - total += bytes; - break; - } - - bytes -= cur->iov_len; - total += cur->iov_len; - *iov_cnt -= 1; - } - - *iov = cur; - return total; -} - -size_t iov_discard_back(struct iovec* iov, unsigned int* iov_cnt, - size_t bytes) -{ - size_t total = 0; - struct iovec* cur; - - if (*iov_cnt == 0) - { - return 0; - } - - cur = iov + (*iov_cnt - 1); - - while (*iov_cnt > 0) - { - if (cur->iov_len > bytes) - { - cur->iov_len -= bytes; - total += bytes; - break; - } - - bytes -= cur->iov_len; - total += cur->iov_len; - cur--; - *iov_cnt -= 1; - } - - return total; -} - -void qemu_iovec_discard_back(QEMUIOVector* qiov, size_t bytes) -{ - unsigned int niov = qiov->niov; - - assert(qiov->size >= bytes); - assert(iov_discard_back(qiov->iov, &niov, bytes) == bytes); - - qiov->niov = niov; - qiov->size -= bytes; -} diff --git a/pcsx2/USB/qemu-usb/iov.h b/pcsx2/USB/qemu-usb/iov.h index 6798b7eff8..64e306341d 100644 --- a/pcsx2/USB/qemu-usb/iov.h +++ b/pcsx2/USB/qemu-usb/iov.h @@ -11,24 +11,13 @@ * the COPYING file in the top-level directory. */ -#include "USB/platcompat.h" +#pragma once -#ifndef IOV_H -#define IOV_H - -#if !defined(_BITS_UIO_H) && !defined(__iovec_defined) /* /usr/include/bits/uio.h */ -struct iovec +struct usb_iovec { void* iov_base; size_t iov_len; }; -#endif - -/** - * count and return data size, in bytes, of an iovec - * starting at `iov' of `iov_cnt' number of elements. - */ -size_t iov_size(const struct iovec* iov, const unsigned int iov_cnt); /** * Copy from single continuous buffer to scatter-gather vector of buffers @@ -47,43 +36,11 @@ size_t iov_size(const struct iovec* iov, const unsigned int iov_cnt); * such "large" value is -1 (sinice size_t is unsigned), * so specifying `-1' as `bytes' means 'up to the end of iovec'. */ -size_t iov_from_buf_full(const struct iovec* iov, unsigned int iov_cnt, +size_t iov_from_buf(const struct usb_iovec* iov, unsigned int iov_cnt, size_t offset, const void* buf, size_t bytes); -size_t iov_to_buf_full(const struct iovec* iov, const unsigned int iov_cnt, +size_t iov_to_buf(const struct usb_iovec* iov, const unsigned int iov_cnt, size_t offset, void* buf, size_t bytes); -static inline size_t -iov_from_buf(const struct iovec* iov, unsigned int iov_cnt, - size_t offset, const void* buf, size_t bytes) -{ - if (__builtin_constant_p(bytes) && iov_cnt && - offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) - { - memcpy((char*)iov[0].iov_base + offset, buf, bytes); - return bytes; - } - else - { - return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes); - } -} - -static inline size_t -iov_to_buf(const struct iovec* iov, const unsigned int iov_cnt, - size_t offset, void* buf, size_t bytes) -{ - if (__builtin_constant_p(bytes) && iov_cnt && - offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) - { - memcpy(buf, (char*)iov[0].iov_base + offset, bytes); - return bytes; - } - else - { - return iov_to_buf_full(iov, iov_cnt, offset, buf, bytes); - } -} - /** * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements, * starting at byte offset `start', to value `fillc', repeating it @@ -94,91 +51,18 @@ iov_to_buf(const struct iovec* iov, const unsigned int iov_cnt, * min(size, iov_size(iov) - offset). * Again, it is okay to use large value for `bytes' to mean "up to the end". */ -size_t iov_memset(const struct iovec* iov, const unsigned int iov_cnt, +size_t iov_memset(const struct usb_iovec* iov, const unsigned int iov_cnt, size_t offset, int fillc, size_t bytes); -/* - * Send/recv data from/to iovec buffers directly - * - * `offset' bytes in the beginning of iovec buffer are skipped and - * next `bytes' bytes are used, which must be within data of iovec. - * - * r = iov_send_recv(sockfd, iov, iovcnt, offset, bytes, true); - * - * is logically equivalent to - * - * char *buf = malloc(bytes); - * iov_to_buf(iov, iovcnt, offset, buf, bytes); - * r = send(sockfd, buf, bytes, 0); - * free(buf); - * - * For iov_send_recv() _whole_ area being sent or received - * should be within the iovec, not only beginning of it. - */ -ssize_t iov_send_recv(int sockfd, const struct iovec* iov, unsigned iov_cnt, - size_t offset, size_t bytes, bool do_send); -#define iov_recv(sockfd, iov, iov_cnt, offset, bytes) \ - iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, false) -#define iov_send(sockfd, iov, iov_cnt, offset, bytes) \ - iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, true) - -/** - * Produce a text hexdump of iovec `iov' with `iov_cnt' number of elements - * in file `fp', prefixing each line with `prefix' and processing not more - * than `limit' data bytes. - */ -void iov_hexdump(const struct iovec* iov, const unsigned int iov_cnt, - FILE* fp, const char* prefix, size_t limit); - -/* - * Partial copy of vector from iov to dst_iov (data is not copied). - * dst_iov overlaps iov at a specified offset. - * size of dst_iov is at most bytes. dst vector count is returned. - */ -unsigned iov_copy(struct iovec* dst_iov, unsigned int dst_iov_cnt, - const struct iovec* iov, unsigned int iov_cnt, - size_t offset, size_t bytes); - -/* - * Remove a given number of bytes from the front or back of a vector. - * This may update iov and/or iov_cnt to exclude iovec elements that are - * no longer required. - * - * The number of bytes actually discarded is returned. This number may be - * smaller than requested if the vector is too small. - */ -size_t iov_discard_front(struct iovec** iov, unsigned int* iov_cnt, - size_t bytes); -size_t iov_discard_back(struct iovec* iov, unsigned int* iov_cnt, - size_t bytes); - typedef struct QEMUIOVector { - struct iovec* iov; + struct usb_iovec* iov; int niov; int nalloc; size_t size; } QEMUIOVector; -void qemu_iovec_init(QEMUIOVector* qiov, int alloc_hint); -void qemu_iovec_init_external(QEMUIOVector* qiov, struct iovec* iov, int niov); +void qemu_iovec_init(QEMUIOVector* qiov); void qemu_iovec_add(QEMUIOVector* qiov, void* base, size_t len); -void qemu_iovec_concat(QEMUIOVector* dst, - QEMUIOVector* src, size_t soffset, size_t sbytes); -size_t qemu_iovec_concat_iov(QEMUIOVector* dst, - struct iovec* src_iov, unsigned int src_cnt, - size_t soffset, size_t sbytes); -bool qemu_iovec_is_zero(QEMUIOVector* qiov); void qemu_iovec_destroy(QEMUIOVector* qiov); void qemu_iovec_reset(QEMUIOVector* qiov); -size_t qemu_iovec_to_buf(QEMUIOVector* qiov, size_t offset, - void* buf, size_t bytes); -size_t qemu_iovec_from_buf(QEMUIOVector* qiov, size_t offset, - const void* buf, size_t bytes); -size_t qemu_iovec_memset(QEMUIOVector* qiov, size_t offset, - int fillc, size_t bytes); -ssize_t qemu_iovec_compare(QEMUIOVector* a, QEMUIOVector* b); -void qemu_iovec_clone(QEMUIOVector* dest, const QEMUIOVector* src, void* buf); -void qemu_iovec_discard_back(QEMUIOVector* qiov, size_t bytes); - -#endif diff --git a/pcsx2/USB/qemu-usb/qusb.h b/pcsx2/USB/qemu-usb/qusb.h index 53d57af491..525ff2970f 100644 --- a/pcsx2/USB/qemu-usb/qusb.h +++ b/pcsx2/USB/qemu-usb/qusb.h @@ -22,8 +22,9 @@ * THE SOFTWARE. */ -#include "iov.h" -#include "queue.h" +#pragma once +#include "USB/qemu-usb/iov.h" +#include "USB/qemu-usb/queue.h" #define USB_TOKEN_SETUP 0x2d #define USB_TOKEN_IN 0x69 /* device -> host */ @@ -388,9 +389,6 @@ typedef struct USBDeviceClass int streams); void (*free_streams)(USBDevice* dev, USBEndpoint** eps, int nr_eps); - int (*open)(USBDevice* dev); - void (*close)(USBDevice* dev); - const char* product_desc; const USBDesc* usb_desc; bool attached_settable; diff --git a/pcsx2/USB/qemu-usb/usb-hub.cpp b/pcsx2/USB/qemu-usb/usb-hub.cpp deleted file mode 100644 index 83d18686ac..0000000000 --- a/pcsx2/USB/qemu-usb/usb-hub.cpp +++ /dev/null @@ -1,594 +0,0 @@ -/* - * QEMU USB HUB emulation - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG - -#define MAX_PORTS 8 - -typedef struct USBHubPort -{ - USBPort port; - uint16_t wPortStatus; - uint16_t wPortChange; -} USBHubPort; - -typedef struct USBHubState -{ - USBDevice dev; - int nb_ports; - USBHubPort ports[MAX_PORTS]; -} USBHubState; - -#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) -#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) -#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) -#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) -#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) -#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) -#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) - -#define PORT_STAT_CONNECTION 0x0001 -#define PORT_STAT_ENABLE 0x0002 -#define PORT_STAT_SUSPEND 0x0004 -#define PORT_STAT_OVERCURRENT 0x0008 -#define PORT_STAT_RESET 0x0010 -#define PORT_STAT_POWER 0x0100 -#define PORT_STAT_LOW_SPEED 0x0200 -#define PORT_STAT_HIGH_SPEED 0x0400 -#define PORT_STAT_TEST 0x0800 -#define PORT_STAT_INDICATOR 0x1000 - -#define PORT_STAT_C_CONNECTION 0x0001 -#define PORT_STAT_C_ENABLE 0x0002 -#define PORT_STAT_C_SUSPEND 0x0004 -#define PORT_STAT_C_OVERCURRENT 0x0008 -#define PORT_STAT_C_RESET 0x0010 - -#define PORT_CONNECTION 0 -#define PORT_ENABLE 1 -#define PORT_SUSPEND 2 -#define PORT_OVERCURRENT 3 -#define PORT_RESET 4 -#define PORT_POWER 8 -#define PORT_LOWSPEED 9 -#define PORT_HIGHSPEED 10 -#define PORT_C_CONNECTION 16 -#define PORT_C_ENABLE 17 -#define PORT_C_SUSPEND 18 -#define PORT_C_OVERCURRENT 19 -#define PORT_C_RESET 20 -#define PORT_TEST 21 -#define PORT_INDICATOR 22 - -/* same as Linux kernel root hubs */ - -static const uint8_t qemu_hub_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x01, /* u16 bcdUSB; v1.1 */ - - 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* u16 idVendor; */ - 0x00, 0x00, /* u16 idProduct; */ - 0x01, 0x01, /* u16 bcdDevice */ - - 0x03, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x01, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ -}; - -/* XXX: patch interrupt size */ -static const uint8_t qemu_hub_config_descriptor[] = { - - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 0x00, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* u8 if_bInterfaceSubClass; */ - 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const uint8_t qemu_hub_hub_descriptor[] = - { - 0x00, /* u8 bLength; patched in later */ - 0x29, /* u8 bDescriptorType; Hub-descriptor */ - 0x00, /* u8 bNbrPorts; (patched later) */ - 0x0a, /* u16 wHubCharacteristics; */ - 0x00, /* (per-port OC, no power switching) */ - 0x01, /* u8 bPwrOn2pwrGood; 2ms */ - 0x00 /* u8 bHubContrCurrent; 0 mA */ - - /* DeviceRemovable and PortPwrCtrlMask patched in later */ -}; - -static void usb_hub_attach(USBPort* port1, USBDevice* dev) -{ - USBHubState* s = (USBHubState*)port1->opaque; - USBHubPort* port = (USBHubPort*)&s->ports[port1->index]; - - if (dev) - { - if (port->port.dev) - usb_attach(port1, NULL); - - port->wPortStatus |= PORT_STAT_CONNECTION; - port->wPortChange |= PORT_STAT_C_CONNECTION; - if (dev->speed == USB_SPEED_LOW) - port->wPortStatus |= PORT_STAT_LOW_SPEED; - else - port->wPortStatus &= ~PORT_STAT_LOW_SPEED; - port->port.dev = dev; - /* send the attach message */ - dev->handle_packet(dev, - USB_MSG_ATTACH, 0, 0, NULL, 0); - } - else - { - dev = port->port.dev; - if (dev) - { - port->wPortStatus &= ~PORT_STAT_CONNECTION; - port->wPortChange |= PORT_STAT_C_CONNECTION; - if (port->wPortStatus & PORT_STAT_ENABLE) - { - port->wPortStatus &= ~PORT_STAT_ENABLE; - port->wPortChange |= PORT_STAT_C_ENABLE; - } - /* send the detach message */ - dev->handle_packet(dev, - USB_MSG_DETACH, 0, 0, NULL, 0); - port->port.dev = NULL; - } - } -} - -static void usb_hub_handle_reset(USBDevice* dev) -{ - /* XXX: do it */ -} - -static int usb_hub_handle_control(USBDevice* dev, int request, int value, - int index, int length, uint8_t* data) -{ - USBHubState* s = (USBHubState*)dev; - int ret; - - switch (request) - { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) - { - dev->remote_wakeup = 0; - } - else - { - goto fail; - } - ret = 0; - break; - case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == 0 && index != 0x81) - { /* clear ep halt */ - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) - { - dev->remote_wakeup = 1; - } - else - { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (value >> 8) - { - case USB_DT_DEVICE: - memcpy(data, qemu_hub_dev_descriptor, - sizeof(qemu_hub_dev_descriptor)); - ret = sizeof(qemu_hub_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_hub_config_descriptor, - sizeof(qemu_hub_config_descriptor)); - - /* status change endpoint size based on number - * of ports */ - data[22] = (s->nb_ports + 1 + 7) / 8; - - ret = sizeof(qemu_hub_config_descriptor); - break; - case USB_DT_STRING: - switch (value & 0xff) - { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* serial number */ - ret = set_usb_string(data, "314159"); - break; - case 2: - /* product description */ - ret = set_usb_string(data, "QEMU USB Hub"); - break; - case 3: - /* vendor description */ - ret = set_usb_string(data, "PCSX2/QEMU"); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; - /* usb specific requests */ - case GetHubStatus: - data[0] = 0; - data[1] = 0; - data[2] = 0; - data[3] = 0; - ret = 4; - break; - case GetPortStatus: - { - unsigned int n = index - 1; - USBHubPort* port; - if (n >= s->nb_ports) - goto fail; - port = &s->ports[n]; - data[0] = port->wPortStatus; - data[1] = port->wPortStatus >> 8; - data[2] = port->wPortChange; - data[3] = port->wPortChange >> 8; - ret = 4; - } - break; - case SetHubFeature: - case ClearHubFeature: - if (value == 0 || value == 1) - { - } - else - { - goto fail; - } - ret = 0; - break; - case SetPortFeature: - { - unsigned int n = index - 1; - USBHubPort* port; - USBDevice* dev; - if (n >= s->nb_ports) - goto fail; - port = &s->ports[n]; - dev = port->port.dev; - switch (value) - { - case PORT_SUSPEND: - port->wPortStatus |= PORT_STAT_SUSPEND; - break; - case PORT_RESET: - if (dev) - { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); - port->wPortChange |= PORT_STAT_C_RESET; - /* set enable bit */ - port->wPortStatus |= PORT_STAT_ENABLE; - } - break; - case PORT_POWER: - break; - default: - goto fail; - } - ret = 0; - } - break; - case ClearPortFeature: - { - unsigned int n = index - 1; - USBHubPort* port; - USBDevice* dev; - if (n >= s->nb_ports) - goto fail; - port = &s->ports[n]; - dev = port->port.dev; - switch (value) - { - case PORT_ENABLE: - port->wPortStatus &= ~PORT_STAT_ENABLE; - break; - case PORT_C_ENABLE: - port->wPortChange &= ~PORT_STAT_C_ENABLE; - break; - case PORT_SUSPEND: - port->wPortStatus &= ~PORT_STAT_SUSPEND; - break; - case PORT_C_SUSPEND: - port->wPortChange &= ~PORT_STAT_C_SUSPEND; - break; - case PORT_C_CONNECTION: - port->wPortChange &= ~PORT_STAT_C_CONNECTION; - break; - case PORT_C_OVERCURRENT: - port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; - break; - case PORT_C_RESET: - port->wPortChange &= ~PORT_STAT_C_RESET; - break; - default: - goto fail; - } - ret = 0; - } - break; - case GetHubDescriptor: - { - unsigned int n, limit, var_hub_size = 0; - memcpy(data, qemu_hub_hub_descriptor, - sizeof(qemu_hub_hub_descriptor)); - data[2] = s->nb_ports; - - /* fill DeviceRemovable bits */ - limit = ((s->nb_ports + 1 + 7) / 8) + 7; - for (n = 7; n < limit; n++) - { - data[n] = 0x00; - var_hub_size++; - } - - /* fill PortPwrCtrlMask bits */ - limit = limit + ((s->nb_ports + 7) / 8); - for (; n < limit; n++) - { - data[n] = 0xff; - var_hub_size++; - } - - ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; - data[0] = ret; - break; - } - default: - fail: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static int usb_hub_handle_data(USBDevice* dev, int pid, - uint8_t devep, uint8_t* data, int len) -{ - int ret = 0; - switch (pid) - { - case USB_TOKEN_IN: - if (devep == 1) - { - USBHubState* s = (USBHubState*)dev; - unsigned int status; - int i, n; - n = (s->nb_ports + 1 + 7) / 8; - if (len == 1) - { /* FreeBSD workaround */ - n = 1; - } - else if (n > len) - { - return USB_RET_BABBLE; - } - status = 0; - for (i = 0; i < s->nb_ports; i++) - { - USBHubPort* port = &s->ports[i]; - if (port->wPortChange) - status |= (1 << (i + 1)); - } - if (status != 0) - { - for (i = 0; i < n; i++) - { - data[i] = status >> (8 * i); - } - ret = n; - } - else - { - ret = USB_RET_NAK; /* usb11 11.13.1 */ - } - } - else - { - goto fail; - } - break; - case USB_TOKEN_OUT: - default: - fail: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static int usb_hub_broadcast_packet(USBHubState* s, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t* data, int len) -{ - for (int i = 0; i < s->nb_ports; i++) - { - USBHubPort* port = &s->ports[i]; - USBDevice* dev = port->port.dev; - if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) - { - int ret = dev->handle_packet(dev, pid, - devaddr, devep, - data, len); - if (ret != USB_RET_NODEV) - { - return ret; - } - } - } - return USB_RET_NODEV; -} - -static int usb_hub_handle_packet(USBDevice* dev, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t* data, int len) -{ - USBHubState* s = (USBHubState*)dev; - - if (dev->state == USB_STATE_DEFAULT && - dev->addr != 0 && - devaddr != dev->addr && - (pid == USB_TOKEN_SETUP || - pid == USB_TOKEN_OUT || - pid == USB_TOKEN_IN)) - { - /* broadcast the packet to the devices */ - return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); - } - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); -} - -static void usb_hub_handle_destroy(USBDevice* dev) -{ - USBHubState* s = (USBHubState*)dev; - - free(s); -} - -USBDevice* usb_hub_init(int nb_ports) -{ - if (nb_ports > MAX_PORTS) - return NULL; - USBHubState* s = (USBHubState*)qemu_mallocz(sizeof(USBHubState)); - if (!s) - return NULL; - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_hub_handle_packet; - - /* generic USB device init */ - s->dev.handle_reset = usb_hub_handle_reset; - s->dev.handle_control = usb_hub_handle_control; - s->dev.handle_data = usb_hub_handle_data; - s->dev.handle_destroy = usb_hub_handle_destroy; - - strncpy(s->dev.devname, "QEMU USB Hub", sizeof(s->dev.devname)); - - s->nb_ports = nb_ports; - for (int i = 0; i < s->nb_ports; i++) - { - USBHubPort* port = &s->ports[i]; - port->port.opaque = s; - port->port.index = i; - port->port.attach = usb_hub_attach; - port->wPortStatus = PORT_STAT_POWER; - port->wPortChange = 0; - } - return (USBDevice*)s; -} diff --git a/pcsx2/USB/qemu-usb/usb-ohci.cpp b/pcsx2/USB/qemu-usb/usb-ohci.cpp index 5e7748c130..1e01997169 100644 --- a/pcsx2/USB/qemu-usb/usb-ohci.cpp +++ b/pcsx2/USB/qemu-usb/usb-ohci.cpp @@ -29,19 +29,20 @@ //typedef CPUReadMemoryFunc #include "PrecompiledHeader.h" -#include "vl.h" -#include "queue.h" -#include "USBinternal.h" +#include "USB/qemu-usb/qusb.h" +#include "USB/qemu-usb/queue.h" +#include "USB/qemu-usb/USBinternal.h" +#include "IopMem.h" #define DMA_DIRECTION_TO_DEVICE 0 #define DMA_DIRECTION_FROM_DEVICE 1 #define ED_LINK_LIMIT 32 -int64_t last_cycle = 0; +extern int64_t g_usb_last_cycle; #define MIN_IRQ_INTERVAL 64 /* hack */ -extern int64_t get_clock(); -extern int get_ticks_per_second(); +extern int64_t usb_get_clock(); +extern int usb_get_ticks_per_second(); extern void usbIrq(int); //#define DEBUG_PACKET @@ -49,6 +50,27 @@ extern void usbIrq(int); static void ohci_async_cancel_device(OHCIState* ohci, USBDevice* dev); +static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union + { + uint64_t ll; + struct + { + uint32_t low, high; + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + /* Update IRQ levels */ static inline void ohci_intr_update(OHCIState* ohci) { @@ -61,10 +83,10 @@ static inline void ohci_intr_update(OHCIState* ohci) if (level) { - if ((get_clock() - last_cycle) > MIN_IRQ_INTERVAL) + if ((usb_get_clock() - g_usb_last_cycle) > MIN_IRQ_INTERVAL) { usbIrq(1); - last_cycle = get_clock(); + g_usb_last_cycle = usb_get_clock(); } } } @@ -334,68 +356,43 @@ void ohci_hard_reset(OHCIState* ohci) ohci_roothub_reset(ohci); } -#define le32_to_cpu(x) (x) -#define cpu_to_le32(x) (x) -#define le16_to_cpu(x) (x) -#define cpu_to_le16(x) (x) - /* Get an array of dwords from main memory */ -static inline int get_dwords(uint32_t addr, uint32_t* buf, int num) +__fi static int get_dwords(uint32_t addr, uint32_t* buf, uint32_t num) { - int i; - - for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) - { - if (cpu_physical_memory_rw(addr, (uint8_t*)buf, sizeof(*buf), 0)) - return 0; - *buf = le32_to_cpu(*buf); - } + if ((addr + (num * sizeof(uint32_t))) > sizeof(iopMem->Main)) + return 0; + std::memcpy(buf, iopMem->Main + addr, num * sizeof(uint32_t)); return 1; } /* Get an array of words from main memory */ -static inline int get_words(uint32_t addr, uint16_t* buf, int num) +__fi static int get_words(uint32_t addr, uint16_t* buf, uint32_t num) { - int i; - - for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) - { - if (cpu_physical_memory_rw(addr, (uint8_t*)buf, sizeof(*buf), 0)) - return 0; - *buf = le16_to_cpu(*buf); - } + if ((addr + (num * sizeof(uint16_t))) > sizeof(iopMem->Main)) + return 0; + std::memcpy(buf, iopMem->Main + addr, num * sizeof(uint16_t)); return 1; } /* Put an array of dwords in to main memory */ -static inline int put_dwords(uint32_t addr, uint32_t* buf, int num) +__fi static int put_dwords(uint32_t addr, uint32_t* buf, uint32_t num) { - int i; - - for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) - { - uint32_t tmp = cpu_to_le32(*buf); - if (cpu_physical_memory_rw(addr, (uint8_t*)&tmp, sizeof(tmp), 1)) - return 0; - } + if ((addr + (num * sizeof(uint32_t))) > sizeof(iopMem->Main)) + return 0; + std::memcpy(iopMem->Main + addr, buf, num * sizeof(uint32_t)); return 1; } /* Put an array of dwords in to main memory */ -static inline int put_words(uint32_t addr, uint16_t* buf, int num) +__fi static int put_words(uint32_t addr, uint16_t* buf, uint32_t num) { - int i; - - for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) - { - uint16_t tmp = cpu_to_le16(*buf); - if (cpu_physical_memory_rw(addr, (uint8_t*)&tmp, sizeof(tmp), 1)) - return 0; - } + if ((addr + (num * sizeof(uint16_t))) > sizeof(iopMem->Main)) + return 0; + std::memcpy(iopMem->Main + addr, buf, num * sizeof(uint16_t)); return 1; } @@ -436,31 +433,35 @@ static inline int ohci_put_iso_td(OHCIState* ohci, uint32_t addr, struct ohci_is put_words(addr + 16, td->offset, 8); } -static inline int ohci_put_hcca(OHCIState* ohci, - struct ohci_hcca* hcca) -{ - cpu_physical_memory_write(ohci->hcca + HCCA_WRITEBACK_OFFSET, - (uint8_t*)hcca + HCCA_WRITEBACK_OFFSET, - HCCA_WRITEBACK_SIZE); - return 1; -} - /* Read/Write the contents of a TD from/to main memory. */ static int ohci_copy_td(OHCIState* ohci, struct ohci_td* td, uint8_t* buf, uint32_t len, int write) { uint32_t ptr, n; ptr = td->cbp; - n = 0x1000 - (ptr & 0xfff); - if (n > len) - n = len; - if (cpu_physical_memory_rw(ptr, buf, n, write)) + n = std::min(0x1000 - (ptr & 0xfff), len); + if ((ptr + n) > sizeof(iopMem->Main)) return 1; + + if (write) + std::memcpy(iopMem->Main + ptr, buf, len); + else + std::memcpy(buf, iopMem->Main + ptr, len); + if (n == len) return 0; ptr = td->be & ~0xfffu; buf += n; - cpu_physical_memory_rw(ptr, buf, len - n, write); + len -= n; + + if ((ptr + n) > sizeof(iopMem->Main)) + return 1; + + if (write) + std::memcpy(iopMem->Main + ptr, buf, len); + else + std::memcpy(buf, iopMem->Main + ptr, len); + return 0; } @@ -471,16 +472,30 @@ static int ohci_copy_iso_td(OHCIState* ohci, uint32_t start_addr, uint32_t end_a uint32_t ptr, n; ptr = start_addr; - n = 0x1000 - (ptr & 0xfff); - if (n > len) - n = len; - if (cpu_physical_memory_rw(ptr, buf, n, write)) + n = std::min(0x1000 - (ptr & 0xfff), len); + + if ((ptr + n) > sizeof(iopMem->Main)) return 1; + + if (write) + std::memcpy(iopMem->Main + ptr, buf, len); + else + std::memcpy(buf, iopMem->Main + ptr, len); + if (n == len) return 0; ptr = end_addr & ~0xfffu; buf += n; - cpu_physical_memory_rw(ptr, buf, len - n, write); + len -= n; + + if ((ptr + n) > sizeof(iopMem->Main)) + return 1; + + if (write) + std::memcpy(iopMem->Main + ptr, buf, len); + else + std::memcpy(buf, iopMem->Main + ptr, len); + return 0; } @@ -488,7 +503,7 @@ static void ohci_process_lists(OHCIState* ohci, int completion); static void ohci_async_complete_packet(USBPort* port, USBPacket* packet) { - OHCIState* ohci = CONTAINER_OF(packet, OHCIState, usb_packet); + OHCIState* ohci = USB_CONTAINER_OF(packet, OHCIState, usb_packet); //trace_usb_ohci_async_complete(); ohci->async_complete = true; @@ -733,7 +748,7 @@ static int ohci_service_iso_td(OHCIState* ohci, struct ohci_ed* ed, } else { - if (ret > (ssize_t)len) + if (ret > static_cast(len)) { //trace_usb_ohci_iso_td_data_overrun(ret, len); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, @@ -1136,8 +1151,8 @@ static int ohci_service_ed_list(OHCIState* ohci, uint32_t head, int completion) /* Generate a SOF event, and set a timer for EOF */ static void ohci_sof(OHCIState* ohci) { - ohci->sof_time = get_clock(); - ohci->eof_timer = usb_frame_time; + ohci->sof_time = usb_get_clock(); + ohci->eof_timer = g_usb_frame_time; ohci_set_interrupt(ohci, OHCI_INTR_SF); } @@ -1170,9 +1185,14 @@ static void ohci_process_lists(OHCIState* ohci, int completion) void ohci_frame_boundary(void* opaque) { OHCIState* ohci = (OHCIState*)opaque; - struct ohci_hcca hcca; - cpu_physical_memory_read(ohci->hcca, (uint8_t*)&hcca, sizeof(hcca)); + if (ohci->hcca + sizeof(ohci_hcca) > sizeof(iopMem->Main)) + { + Console.Error("ohci->hcca pointer is out of range."); + return; + } + + ohci_hcca* hcca = reinterpret_cast(iopMem->Main + ohci->hcca); /* Process all the lists at the end of the frame */ /* if reset bit was set, don't process possibly invalid descriptors */ @@ -1183,7 +1203,7 @@ void ohci_frame_boundary(void* opaque) if (ohci->ctl & OHCI_CTL_PLE) { const int n = ohci->frame_number & 0x1f; - ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); + ohci_service_ed_list(ohci, hcca->intr[n], 0); } /* Cancel all pending packets if either of the lists has been disabled. */ @@ -1210,7 +1230,7 @@ void ohci_frame_boundary(void* opaque) /* Increment frame number and take care of endianness. */ ohci->frame_number = (ohci->frame_number + 1) & 0xffff; - hcca.frame = cpu_to_le16(ohci->frame_number); + hcca->frame = ohci->frame_number; if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { @@ -1218,7 +1238,7 @@ void ohci_frame_boundary(void* opaque) abort(); if (ohci->intr & ohci->intr_status) ohci->done |= 1; - hcca.done = cpu_to_le32(ohci->done); + hcca->done = ohci->done; ohci->done = 0; ohci->done_count = 7; ohci_set_interrupt(ohci, OHCI_INTR_WD); @@ -1229,9 +1249,6 @@ void ohci_frame_boundary(void* opaque) /* Do SOF stuff here */ ohci_sof(ohci); - - /* Writeback HCCA */ - ohci_put_hcca(ohci, &hcca); } /* Start sending SOF tokens across the USB bus, lists are processed in @@ -1361,13 +1378,13 @@ static uint32_t ohci_get_frame_remaining(OHCIState* ohci) /* Being in USB operational state guarnatees sof_time was * set already. */ - tks = get_clock() - ohci->sof_time; + tks = usb_get_clock() - ohci->sof_time; /* avoid muldiv if possible */ - if (tks >= usb_frame_time) + if (tks >= g_usb_frame_time) return (ohci->frt << 31); - tks = muldiv64(1, tks, usb_bit_time); + tks = muldiv64(1, tks, g_usb_bit_time); fr = (uint16_t)(ohci->fi - tks); return (ohci->frt << 31) | fr; @@ -1717,26 +1734,26 @@ OHCIState* ohci_create(uint32_t base, int ports) return NULL; int i; - const int ticks_per_sec = get_ticks_per_second(); + const int ticks_per_sec = usb_get_ticks_per_second(); memset(ohci, 0, sizeof(OHCIState)); ohci->mem_base = base; - if (usb_frame_time == 0) + if (g_usb_frame_time == 0) { #if OHCI_TIME_WARP - usb_frame_time = ticks_per_sec; - usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ / 1000); + g_usb_frame_time = ticks_per_sec; + g_usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ / 1000); #else - usb_frame_time = muldiv64(1, ticks_per_sec, 1000); + g_usb_frame_time = muldiv64(1, ticks_per_sec, 1000); if (ticks_per_sec >= USB_HZ) { - usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); + g_usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); } else { - usb_bit_time = 1; + g_usb_bit_time = 1; } #endif } diff --git a/pcsx2/USB/qemu-usb/vl.cpp b/pcsx2/USB/qemu-usb/vl.cpp deleted file mode 100644 index 01971a233e..0000000000 --- a/pcsx2/USB/qemu-usb/vl.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "vl.h" - -/* compute with 96 bit intermediate result: (a*b)/c */ -uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) -{ - union - { - uint64_t ll; - struct - { -#ifdef WORDS_BIGENDIAN - uint32_t high, low; -#else - uint32_t low, high; -#endif - } l; - } u, res; - uint64_t rl, rh; - - u.ll = a; - rl = (uint64_t)u.l.low * (uint64_t)b; - rh = (uint64_t)u.l.high * (uint64_t)b; - rh += (rl >> 32); - res.l.high = rh / c; - res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; - return res.ll; -} diff --git a/pcsx2/USB/qemu-usb/vl.h b/pcsx2/USB/qemu-usb/vl.h deleted file mode 100644 index 1df9cbcd12..0000000000 --- a/pcsx2/USB/qemu-usb/vl.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * QEMU System Emulator header - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef VL_H -#define VL_H - -/* we put basic includes here to avoid repeating them in device drivers */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(_MSC_VER) -#define inline __inline -#endif - -#include "qusb.h" - -#ifndef glue -#define xglue(x, y) x##y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s -#endif - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -/* vl.c */ -uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); -int cpu_physical_memory_rw(uint32_t addr, uint8_t* buf, - size_t len, int is_write); - -inline int cpu_physical_memory_read(uint32_t addr, - uint8_t* buf, size_t len) -{ - return cpu_physical_memory_rw(addr, buf, len, 0); -} - -inline int cpu_physical_memory_write(uint32_t addr, - const uint8_t* buf, size_t len) -{ - return cpu_physical_memory_rw(addr, (uint8_t*)buf, len, 1); -} - -#endif /* VL_H */ diff --git a/pcsx2/USB/shared/hidapi.cpp b/pcsx2/USB/shared/hidapi.cpp deleted file mode 100644 index 888bc4209b..0000000000 --- a/pcsx2/USB/shared/hidapi.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include -#include -#include "hidapi.h" - -_HidD_GetHidGuid HidD_GetHidGuid = NULL; -_HidD_GetAttributes HidD_GetAttributes = NULL; -_HidD_GetPreparsedData HidD_GetPreparsedData = NULL; -_HidP_GetCaps HidP_GetCaps = NULL; -_HidD_FreePreparsedData HidD_FreePreparsedData = NULL; -_HidD_GetFeature HidD_GetFeature = NULL; -_HidD_SetFeature HidD_SetFeature = NULL; -_HidP_GetSpecificButtonCaps HidP_GetSpecificButtonCaps = NULL; -_HidP_GetButtonCaps HidP_GetButtonCaps = NULL; -_HidP_GetUsages HidP_GetUsages = NULL; -_HidP_GetValueCaps HidP_GetValueCaps = NULL; -_HidP_GetUsageValue HidP_GetUsageValue = NULL; -_HidD_GetProductString HidD_GetProductString = NULL; - -static HMODULE hModHid = 0; - -int InitHid() -{ - if (hModHid) - { - return 1; - } - hModHid = LoadLibraryA("hid.dll"); - if (hModHid) - { - if ((HidD_GetHidGuid = (_HidD_GetHidGuid)GetProcAddress(hModHid, "HidD_GetHidGuid")) && - (HidD_GetAttributes = (_HidD_GetAttributes)GetProcAddress(hModHid, "HidD_GetAttributes")) && - (HidD_GetPreparsedData = (_HidD_GetPreparsedData)GetProcAddress(hModHid, "HidD_GetPreparsedData")) && - (HidP_GetCaps = (_HidP_GetCaps)GetProcAddress(hModHid, "HidP_GetCaps")) && - (HidD_FreePreparsedData = (_HidD_FreePreparsedData)GetProcAddress(hModHid, "HidD_FreePreparsedData")) && - (HidP_GetSpecificButtonCaps = (_HidP_GetSpecificButtonCaps)GetProcAddress(hModHid, "HidP_GetSpecificButtonCaps")) && - (HidP_GetButtonCaps = (_HidP_GetButtonCaps)GetProcAddress(hModHid, "HidP_GetButtonCaps")) && - (HidP_GetUsages = (_HidP_GetUsages)GetProcAddress(hModHid, "HidP_GetUsages")) && - (HidP_GetValueCaps = (_HidP_GetValueCaps)GetProcAddress(hModHid, "HidP_GetValueCaps")) && - (HidP_GetUsageValue = (_HidP_GetUsageValue)GetProcAddress(hModHid, "HidP_GetUsageValue")) && - (HidD_GetProductString = (_HidD_GetProductString)GetProcAddress(hModHid, "HidD_GetProductString")) && - (HidD_GetFeature = (_HidD_GetFeature)GetProcAddress(hModHid, "HidD_GetFeature")) && - (HidD_SetFeature = (_HidD_SetFeature)GetProcAddress(hModHid, "HidD_SetFeature"))) - { - //pHidD_GetHidGuid(&GUID_DEVINTERFACE_HID); - return 1; - } - UninitHid(); - } - return 0; -} - -void UninitHid() -{ - if (hModHid) - { - FreeLibrary(hModHid); - hModHid = 0; - } -} diff --git a/pcsx2/USB/shared/hidapi.h b/pcsx2/USB/shared/hidapi.h deleted file mode 100644 index 2d5c798e32..0000000000 --- a/pcsx2/USB/shared/hidapi.h +++ /dev/null @@ -1,476 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef HIDAPI_H -#define HIDAPI_H - -#include - -#define NTSTATUS int - -typedef USHORT USAGE, *PUSAGE; - -#define HID_USAGE_PAGE_GENERIC ((USAGE)0x01) -#define HID_USAGE_PAGE_SIMULATION ((USAGE)0x02) -#define HID_USAGE_PAGE_VR ((USAGE)0x03) -#define HID_USAGE_PAGE_SPORT ((USAGE)0x04) -#define HID_USAGE_PAGE_GAME ((USAGE)0x05) -#define HID_USAGE_PAGE_KEYBOARD ((USAGE)0x07) -#define HID_USAGE_PAGE_LED ((USAGE)0x08) -#define HID_USAGE_PAGE_BUTTON ((USAGE)0x09) -#define HID_USAGE_PAGE_ORDINAL ((USAGE)0x0A) -#define HID_USAGE_PAGE_TELEPHONY ((USAGE)0x0B) -#define HID_USAGE_PAGE_CONSUMER ((USAGE)0x0C) -#define HID_USAGE_PAGE_DIGITIZER ((USAGE)0x0D) -#define HID_USAGE_PAGE_UNICODE ((USAGE)0x10) -#define HID_USAGE_PAGE_ALPHANUMERIC ((USAGE)0x14) - - -// -// Usages from Generic Desktop Page (0x01) -// - -#define HID_USAGE_GENERIC_POINTER ((USAGE)0x01) -#define HID_USAGE_GENERIC_MOUSE ((USAGE)0x02) -#define HID_USAGE_GENERIC_JOYSTICK ((USAGE)0x04) -#define HID_USAGE_GENERIC_GAMEPAD ((USAGE)0x05) -#define HID_USAGE_GENERIC_KEYBOARD ((USAGE)0x06) -#define HID_USAGE_GENERIC_KEYPAD ((USAGE)0x07) -#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE)0x80) - -#define HID_USAGE_GENERIC_X ((USAGE)0x30) -#define HID_USAGE_GENERIC_Y ((USAGE)0x31) -#define HID_USAGE_GENERIC_Z ((USAGE)0x32) -#define HID_USAGE_GENERIC_RX ((USAGE)0x33) -#define HID_USAGE_GENERIC_RY ((USAGE)0x34) -#define HID_USAGE_GENERIC_RZ ((USAGE)0x35) -#define HID_USAGE_GENERIC_SLIDER ((USAGE)0x36) -#define HID_USAGE_GENERIC_DIAL ((USAGE)0x37) -#define HID_USAGE_GENERIC_WHEEL ((USAGE)0x38) -#define HID_USAGE_GENERIC_HATSWITCH ((USAGE)0x39) -#define HID_USAGE_GENERIC_COUNTED_BUFFER ((USAGE)0x3A) -#define HID_USAGE_GENERIC_BYTE_COUNT ((USAGE)0x3B) -#define HID_USAGE_GENERIC_MOTION_WAKEUP ((USAGE)0x3C) -#define HID_USAGE_GENERIC_VX ((USAGE)0x40) -#define HID_USAGE_GENERIC_VY ((USAGE)0x41) -#define HID_USAGE_GENERIC_VZ ((USAGE)0x42) -#define HID_USAGE_GENERIC_VBRX ((USAGE)0x43) -#define HID_USAGE_GENERIC_VBRY ((USAGE)0x44) -#define HID_USAGE_GENERIC_VBRZ ((USAGE)0x45) -#define HID_USAGE_GENERIC_VNO ((USAGE)0x46) -#define HID_USAGE_GENERIC_SYSCTL_POWER ((USAGE)0x81) -#define HID_USAGE_GENERIC_SYSCTL_SLEEP ((USAGE)0x82) -#define HID_USAGE_GENERIC_SYSCTL_WAKE ((USAGE)0x83) -#define HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU ((USAGE)0x84) -#define HID_USAGE_GENERIC_SYSCTL_MAIN_MENU ((USAGE)0x85) -#define HID_USAGE_GENERIC_SYSCTL_APP_MENU ((USAGE)0x86) -#define HID_USAGE_GENERIC_SYSCTL_HELP_MENU ((USAGE)0x87) -#define HID_USAGE_GENERIC_SYSCTL_MENU_EXIT ((USAGE)0x88) -#define HID_USAGE_GENERIC_SYSCTL_MENU_SELECT ((USAGE)0x89) -#define HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT ((USAGE)0x8A) -#define HID_USAGE_GENERIC_SYSCTL_MENU_LEFT ((USAGE)0x8B) -#define HID_USAGE_GENERIC_SYSCTL_MENU_UP ((USAGE)0x8C) -#define HID_USAGE_GENERIC_SYSCTL_MENU_DOWN ((USAGE)0x8D) - -// -// Usages from Simulation Controls Page (0x02) -// - -#define HID_USAGE_SIMULATION_RUDDER ((USAGE)0xBA) -#define HID_USAGE_SIMULATION_THROTTLE ((USAGE)0xBB) - -// -// Virtual Reality Controls Page (0x03) -// - - -// -// Sport Controls Page (0x04) -// - - -// -// Game Controls Page (0x05) -// - - -// -// Keyboard/Keypad Page (0x07) -// - -// Error "keys" -#define HID_USAGE_KEYBOARD_NOEVENT ((USAGE)0x00) -#define HID_USAGE_KEYBOARD_ROLLOVER ((USAGE)0x01) -#define HID_USAGE_KEYBOARD_POSTFAIL ((USAGE)0x02) -#define HID_USAGE_KEYBOARD_UNDEFINED ((USAGE)0x03) - -// Letters -#define HID_USAGE_KEYBOARD_aA ((USAGE)0x04) -#define HID_USAGE_KEYBOARD_zZ ((USAGE)0x1D) -// Numbers -#define HID_USAGE_KEYBOARD_ONE ((USAGE)0x1E) -#define HID_USAGE_KEYBOARD_ZERO ((USAGE)0x27) -// Modifier Keys -#define HID_USAGE_KEYBOARD_LCTRL ((USAGE)0xE0) -#define HID_USAGE_KEYBOARD_LSHFT ((USAGE)0xE1) -#define HID_USAGE_KEYBOARD_LALT ((USAGE)0xE2) -#define HID_USAGE_KEYBOARD_LGUI ((USAGE)0xE3) -#define HID_USAGE_KEYBOARD_RCTRL ((USAGE)0xE4) -#define HID_USAGE_KEYBOARD_RSHFT ((USAGE)0xE5) -#define HID_USAGE_KEYBOARD_RALT ((USAGE)0xE6) -#define HID_USAGE_KEYBOARD_RGUI ((USAGE)0xE7) -#define HID_USAGE_KEYBOARD_SCROLL_LOCK ((USAGE)0x47) -#define HID_USAGE_KEYBOARD_NUM_LOCK ((USAGE)0x53) -#define HID_USAGE_KEYBOARD_CAPS_LOCK ((USAGE)0x39) -// Funtion keys -#define HID_USAGE_KEYBOARD_F1 ((USAGE)0x3A) -#define HID_USAGE_KEYBOARD_F12 ((USAGE)0x45) - -#define HID_USAGE_KEYBOARD_RETURN ((USAGE)0x28) -#define HID_USAGE_KEYBOARD_ESCAPE ((USAGE)0x29) -#define HID_USAGE_KEYBOARD_DELETE ((USAGE)0x2A) - -#define HID_USAGE_KEYBOARD_PRINT_SCREEN ((USAGE)0x46) - -// and hundreds more... - -// -// LED Page (0x08) -// - -#define HID_USAGE_LED_NUM_LOCK ((USAGE)0x01) -#define HID_USAGE_LED_CAPS_LOCK ((USAGE)0x02) -#define HID_USAGE_LED_SCROLL_LOCK ((USAGE)0x03) -#define HID_USAGE_LED_COMPOSE ((USAGE)0x04) -#define HID_USAGE_LED_KANA ((USAGE)0x05) -#define HID_USAGE_LED_POWER ((USAGE)0x06) -#define HID_USAGE_LED_SHIFT ((USAGE)0x07) -#define HID_USAGE_LED_DO_NOT_DISTURB ((USAGE)0x08) -#define HID_USAGE_LED_MUTE ((USAGE)0x09) -#define HID_USAGE_LED_TONE_ENABLE ((USAGE)0x0A) -#define HID_USAGE_LED_HIGH_CUT_FILTER ((USAGE)0x0B) -#define HID_USAGE_LED_LOW_CUT_FILTER ((USAGE)0x0C) -#define HID_USAGE_LED_EQUALIZER_ENABLE ((USAGE)0x0D) -#define HID_USAGE_LED_SOUND_FIELD_ON ((USAGE)0x0E) -#define HID_USAGE_LED_SURROUND_FIELD_ON ((USAGE)0x0F) -#define HID_USAGE_LED_REPEAT ((USAGE)0x10) -#define HID_USAGE_LED_STEREO ((USAGE)0x11) -#define HID_USAGE_LED_SAMPLING_RATE_DETECT ((USAGE)0x12) -#define HID_USAGE_LED_SPINNING ((USAGE)0x13) -#define HID_USAGE_LED_CAV ((USAGE)0x14) -#define HID_USAGE_LED_CLV ((USAGE)0x15) -#define HID_USAGE_LED_RECORDING_FORMAT_DET ((USAGE)0x16) -#define HID_USAGE_LED_OFF_HOOK ((USAGE)0x17) -#define HID_USAGE_LED_RING ((USAGE)0x18) -#define HID_USAGE_LED_MESSAGE_WAITING ((USAGE)0x19) -#define HID_USAGE_LED_DATA_MODE ((USAGE)0x1A) -#define HID_USAGE_LED_BATTERY_OPERATION ((USAGE)0x1B) -#define HID_USAGE_LED_BATTERY_OK ((USAGE)0x1C) -#define HID_USAGE_LED_BATTERY_LOW ((USAGE)0x1D) -#define HID_USAGE_LED_SPEAKER ((USAGE)0x1E) -#define HID_USAGE_LED_HEAD_SET ((USAGE)0x1F) -#define HID_USAGE_LED_HOLD ((USAGE)0x20) -#define HID_USAGE_LED_MICROPHONE ((USAGE)0x21) -#define HID_USAGE_LED_COVERAGE ((USAGE)0x22) -#define HID_USAGE_LED_NIGHT_MODE ((USAGE)0x23) -#define HID_USAGE_LED_SEND_CALLS ((USAGE)0x24) -#define HID_USAGE_LED_CALL_PICKUP ((USAGE)0x25) -#define HID_USAGE_LED_CONFERENCE ((USAGE)0x26) -#define HID_USAGE_LED_STAND_BY ((USAGE)0x27) -#define HID_USAGE_LED_CAMERA_ON ((USAGE)0x28) -#define HID_USAGE_LED_CAMERA_OFF ((USAGE)0x29) -#define HID_USAGE_LED_ON_LINE ((USAGE)0x2A) -#define HID_USAGE_LED_OFF_LINE ((USAGE)0x2B) -#define HID_USAGE_LED_BUSY ((USAGE)0x2C) -#define HID_USAGE_LED_READY ((USAGE)0x2D) -#define HID_USAGE_LED_PAPER_OUT ((USAGE)0x2E) -#define HID_USAGE_LED_PAPER_JAM ((USAGE)0x2F) -#define HID_USAGE_LED_REMOTE ((USAGE)0x30) -#define HID_USAGE_LED_FORWARD ((USAGE)0x31) -#define HID_USAGE_LED_REVERSE ((USAGE)0x32) -#define HID_USAGE_LED_STOP ((USAGE)0x33) -#define HID_USAGE_LED_REWIND ((USAGE)0x34) -#define HID_USAGE_LED_FAST_FORWARD ((USAGE)0x35) -#define HID_USAGE_LED_PLAY ((USAGE)0x36) -#define HID_USAGE_LED_PAUSE ((USAGE)0x37) -#define HID_USAGE_LED_RECORD ((USAGE)0x38) -#define HID_USAGE_LED_ERROR ((USAGE)0x39) -#define HID_USAGE_LED_SELECTED_INDICATOR ((USAGE)0x3A) -#define HID_USAGE_LED_IN_USE_INDICATOR ((USAGE)0x3B) -#define HID_USAGE_LED_MULTI_MODE_INDICATOR ((USAGE)0x3C) -#define HID_USAGE_LED_INDICATOR_ON ((USAGE)0x3D) -#define HID_USAGE_LED_INDICATOR_FLASH ((USAGE)0x3E) -#define HID_USAGE_LED_INDICATOR_SLOW_BLINK ((USAGE)0x3F) -#define HID_USAGE_LED_INDICATOR_FAST_BLINK ((USAGE)0x40) -#define HID_USAGE_LED_INDICATOR_OFF ((USAGE)0x41) -#define HID_USAGE_LED_FLASH_ON_TIME ((USAGE)0x42) -#define HID_USAGE_LED_SLOW_BLINK_ON_TIME ((USAGE)0x43) -#define HID_USAGE_LED_SLOW_BLINK_OFF_TIME ((USAGE)0x44) -#define HID_USAGE_LED_FAST_BLINK_ON_TIME ((USAGE)0x45) -#define HID_USAGE_LED_FAST_BLINK_OFF_TIME ((USAGE)0x46) -#define HID_USAGE_LED_INDICATOR_COLOR ((USAGE)0x47) -#define HID_USAGE_LED_RED ((USAGE)0x48) -#define HID_USAGE_LED_GREEN ((USAGE)0x49) -#define HID_USAGE_LED_AMBER ((USAGE)0x4A) -#define HID_USAGE_LED_GENERIC_INDICATOR ((USAGE)0x3B) - -// -// Button Page (0x09) -// -// There is no need to label these usages. -// - - -// -// Ordinal Page (0x0A) -// -// There is no need to label these usages. -// - - -// -// Telephony Device Page (0x0B) -// - -#define HID_USAGE_TELEPHONY_PHONE ((USAGE)0x01) -#define HID_USAGE_TELEPHONY_ANSWERING_MACHINE ((USAGE)0x02) -#define HID_USAGE_TELEPHONY_MESSAGE_CONTROLS ((USAGE)0x03) -#define HID_USAGE_TELEPHONY_HANDSET ((USAGE)0x04) -#define HID_USAGE_TELEPHONY_HEADSET ((USAGE)0x05) -#define HID_USAGE_TELEPHONY_KEYPAD ((USAGE)0x06) -#define HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON ((USAGE)0x07) - -// BUGBUG defined in ntstatus.h -#ifndef FACILITY_HID_ERROR_CODE -#define FACILITY_HID_ERROR_CODE 0x11 -#endif - -#define HIDP_ERROR_CODES(SEV, CODE) \ - ((NTSTATUS)(((SEV) << 28) | (FACILITY_HID_ERROR_CODE << 16) | (CODE))) - -#define HIDP_STATUS_SUCCESS (HIDP_ERROR_CODES(0x0, 0)) -#define HIDP_STATUS_NULL (HIDP_ERROR_CODES(0x8, 1)) -#define HIDP_STATUS_INVALID_PREPARSED_DATA (HIDP_ERROR_CODES(0xC, 1)) -#define HIDP_STATUS_INVALID_REPORT_TYPE (HIDP_ERROR_CODES(0xC, 2)) -#define HIDP_STATUS_INVALID_REPORT_LENGTH (HIDP_ERROR_CODES(0xC, 3)) -#define HIDP_STATUS_USAGE_NOT_FOUND (HIDP_ERROR_CODES(0xC, 4)) -#define HIDP_STATUS_VALUE_OUT_OF_RANGE (HIDP_ERROR_CODES(0xC, 5)) -#define HIDP_STATUS_BAD_LOG_PHY_VALUES (HIDP_ERROR_CODES(0xC, 6)) -#define HIDP_STATUS_BUFFER_TOO_SMALL (HIDP_ERROR_CODES(0xC, 7)) -#define HIDP_STATUS_INTERNAL_ERROR (HIDP_ERROR_CODES(0xC, 8)) -#define HIDP_STATUS_I8242_TRANS_UNKNOWN (HIDP_ERROR_CODES(0xC, 9)) -#define HIDP_STATUS_INCOMPATIBLE_REPORT_ID (HIDP_ERROR_CODES(0xC, 0xA)) -#define HIDP_STATUS_NOT_VALUE_ARRAY (HIDP_ERROR_CODES(0xC, 0xB)) -#define HIDP_STATUS_IS_VALUE_ARRAY (HIDP_ERROR_CODES(0xC, 0xC)) -#define HIDP_STATUS_DATA_INDEX_NOT_FOUND (HIDP_ERROR_CODES(0xC, 0xD)) -#define HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE (HIDP_ERROR_CODES(0xC, 0xE)) -#define HIDP_STATUS_BUTTON_NOT_PRESSED (HIDP_ERROR_CODES(0xC, 0xF)) -#define HIDP_STATUS_REPORT_DOES_NOT_EXIST (HIDP_ERROR_CODES(0xC, 0x10)) -#define HIDP_STATUS_NOT_IMPLEMENTED (HIDP_ERROR_CODES(0xC, 0x20)) - -typedef enum _HIDP_REPORT_TYPE -{ - HidP_Input, - HidP_Output, - HidP_Feature -} HIDP_REPORT_TYPE; - -typedef struct _USAGE_AND_PAGE -{ - USAGE Usage; - USAGE UsagePage; -} USAGE_AND_PAGE, *PUSAGE_AND_PAGE; - -typedef struct _HIDP_BUTTON_CAPS -{ - USAGE UsagePage; - UCHAR ReportID; - BOOLEAN IsAlias; - - USHORT BitField; - USHORT LinkCollection; // A unique internal index pointer - - USAGE LinkUsage; - USAGE LinkUsagePage; - - BOOLEAN IsRange; - BOOLEAN IsStringRange; - BOOLEAN IsDesignatorRange; - BOOLEAN IsAbsolute; - - ULONG Reserved[10]; - union - { - struct - { - USAGE UsageMin, UsageMax; - USHORT StringMin, StringMax; - USHORT DesignatorMin, DesignatorMax; - USHORT DataIndexMin, DataIndexMax; - } Range; - struct - { - USAGE Usage, Reserved1; - USHORT StringIndex, Reserved2; - USHORT DesignatorIndex, Reserved3; - USHORT DataIndex, Reserved4; - } NotRange; - }; - -} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS; - - -typedef struct _HIDP_VALUE_CAPS -{ - USAGE UsagePage; - UCHAR ReportID; - BOOLEAN IsAlias; - - USHORT BitField; - USHORT LinkCollection; // A unique internal index pointer - - USAGE LinkUsage; - USAGE LinkUsagePage; - - BOOLEAN IsRange; - BOOLEAN IsStringRange; - BOOLEAN IsDesignatorRange; - BOOLEAN IsAbsolute; - - BOOLEAN HasNull; // Does this channel have a null report union - UCHAR Reserved; - USHORT BitSize; // How many bits are devoted to this value? - - USHORT ReportCount; // See Note below. Usually set to 1. - USHORT Reserved2[5]; - - ULONG UnitsExp; - ULONG Units; - - LONG LogicalMin, LogicalMax; - LONG PhysicalMin, PhysicalMax; - - union - { - struct - { - USAGE UsageMin, UsageMax; - USHORT StringMin, StringMax; - USHORT DesignatorMin, DesignatorMax; - USHORT DataIndexMin, DataIndexMax; - } Range; - - struct - { - USAGE Usage, Reserved1; - USHORT StringIndex, Reserved2; - USHORT DesignatorIndex, Reserved3; - USHORT DataIndex, Reserved4; - } NotRange; - }; -} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; - -typedef struct _HIDD_ATTRIBUTES -{ - ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES) - - // - // Vendor ids of this hid device - // - USHORT VendorID; - USHORT ProductID; - USHORT VersionNumber; - - // - // Additional fields will be added to the end of this structure. - // -} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; - -typedef PUCHAR PHIDP_REPORT_DESCRIPTOR; -typedef struct _HIDP_PREPARSED_DATA* PHIDP_PREPARSED_DATA; - - -typedef struct _HIDP_CAPS -{ - USAGE Usage; - USAGE UsagePage; - USHORT InputReportByteLength; - USHORT OutputReportByteLength; - USHORT FeatureReportByteLength; - USHORT Reserved[17]; - - USHORT NumberLinkCollectionNodes; - - USHORT NumberInputButtonCaps; - USHORT NumberInputValueCaps; - USHORT NumberInputDataIndices; - - USHORT NumberOutputButtonCaps; - USHORT NumberOutputValueCaps; - USHORT NumberOutputDataIndices; - - USHORT NumberFeatureButtonCaps; - USHORT NumberFeatureValueCaps; - USHORT NumberFeatureDataIndices; -} HIDP_CAPS, *PHIDP_CAPS; - -typedef struct _HIDP_DATA -{ - USHORT DataIndex; - USHORT Reserved; - union - { - ULONG RawValue; // for values - BOOLEAN On; // for buttons MUST BE TRUE for buttons. - }; -} HIDP_DATA, *PHIDP_DATA; - -typedef BOOLEAN(__stdcall* _HidD_GetAttributes)(HANDLE HidDeviceObject, HIDD_ATTRIBUTES* Attributes); -typedef void(__stdcall* _HidD_GetHidGuid)(GUID* HidGuid); -typedef BOOLEAN(__stdcall* _HidD_GetPreparsedData)(HANDLE HidDeviceObject, PHIDP_PREPARSED_DATA* PreparsedData); -typedef NTSTATUS(__stdcall* _HidP_GetCaps)(PHIDP_PREPARSED_DATA PreparsedData, HIDP_CAPS* caps); -typedef BOOLEAN(__stdcall* _HidD_FreePreparsedData)(PHIDP_PREPARSED_DATA PreparsedData); -typedef BOOLEAN(__stdcall* _HidD_GetFeature)(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength); -typedef BOOLEAN(__stdcall* _HidD_SetFeature)(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength); -typedef NTSTATUS(__stdcall* _HidP_GetSpecificButtonCaps)(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData); -typedef NTSTATUS(__stdcall* _HidP_GetButtonCaps)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData); -typedef NTSTATUS(__stdcall* _HidP_GetUsages)(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE* UsageList, ULONG* UsageLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); -typedef NTSTATUS(__stdcall* _HidP_GetValueCaps)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData); -typedef NTSTATUS(__stdcall* _HidP_GetUsageValue)(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); -typedef BOOLEAN(__stdcall* _HidD_GetProductString)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); - -//#define HidP_GetButtonCaps(_Type_, _Caps_, _Len_, _Data_) \ -// HidP_GetSpecificButtonCaps(_Type_, 0, 0, 0, _Caps_, _Len_, _Data_) - -extern _HidD_GetHidGuid HidD_GetHidGuid; -extern _HidD_GetAttributes HidD_GetAttributes; -extern _HidD_GetPreparsedData HidD_GetPreparsedData; -extern _HidP_GetCaps HidP_GetCaps; -extern _HidD_FreePreparsedData HidD_FreePreparsedData; -extern _HidD_GetFeature HidD_GetFeature; -extern _HidD_SetFeature HidD_SetFeature; -extern _HidP_GetSpecificButtonCaps HidP_GetSpecificButtonCaps; -extern _HidP_GetButtonCaps HidP_GetButtonCaps; -extern _HidP_GetUsages HidP_GetUsages; -extern _HidP_GetValueCaps HidP_GetValueCaps; -extern _HidP_GetUsageValue HidP_GetUsageValue; -extern _HidD_GetProductString HidD_GetProductString; - -void UninitHid(); -int InitHid(); - -#include - -#endif diff --git a/pcsx2/USB/shared/inifile_usb.cpp b/pcsx2/USB/shared/inifile_usb.cpp deleted file mode 100644 index c18dab9f9d..0000000000 --- a/pcsx2/USB/shared/inifile_usb.cpp +++ /dev/null @@ -1,1058 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "inifile_usb.h" -#include -#include -#include - -// Only valid if C++ -#ifndef __cplusplus -#error C++ compiler required. -#endif - -// In the event you want to trace the calls can define _TRACE_CINIFILE -#ifdef _TRACE_CINIFILE -#define _CINIFILE_DEBUG -#endif - -// _CRLF is used in the Save() function -// The class will read the correct data regardless of how the file linefeeds are defined or -// It is best to use the linefeed that is default to the system. This reduces issues if needing to modify -// the file with ie. notepad.exe which doesn't recognize unix linefeeds. -#ifdef _WIN32 // Windows default is \r\n -#ifdef _FORCE_UNIX_LINEFEED -#define _CRLFA "\n" -#define _CRLFW L"\n" -#else -#define _CRLFA "\r\n" -#define _CRLFW L"\r\n" -#endif - -#else // Standard format is \n for unix -#ifdef _FORCE_WINDOWS_LINEFEED -#define _CRLFA "\r\n" -#define _CRLFW L"\r\n" -#else -#define _CRLFA "\n" -#define _CRLFW L"\n" -#endif -#endif - -// Convert wstring to string -std::string wstr_to_str(const std::wstring& arg) -{ - std::string res(arg.length(), '\0'); - wcstombs(const_cast(res.data()), arg.c_str(), arg.length()); - return res; -} - -// Convert string to wstring -std::wstring str_to_wstr(const std::string& arg) -{ - std::wstring res(arg.length(), L'\0'); - mbstowcs(const_cast(res.data()), arg.c_str(), arg.length()); - return res; -} - -// Helper Functions -void RTrim(std::string& str, const std::string& chars = " \t") -{ - str.erase(str.find_last_not_of(chars) + 1); -} - -void LTrim(std::string& str, const std::string& chars = " \t") -{ - str.erase(0, str.find_first_not_of(chars)); -} - -void Trim(std::string& str, const std::string& chars = " \t") -{ - str.erase(str.find_last_not_of(chars) + 1); - str.erase(0, str.find_first_not_of(chars)); -} - -// Stream Helpers - -std::ostream& operator<<(std::ostream& output, CIniFileA& obj) -{ - obj.Save(output); - return output; -} - -std::istream& operator>>(std::istream& input, CIniFileA& obj) -{ - obj.Load(input); - return input; -} - -std::istream& operator>>(std::istream& input, CIniMergeA merger) -{ - return merger(input); -} - -// CIniFileA class methods - -CIniFileA::CIniFileA() -{ -} - -CIniFileA::~CIniFileA() -{ - RemoveAllSections(); -} - -const char* const CIniFileA::LF = _CRLFA; - -void CIniFileA::Save(std::ostream& output) -{ - std::string sSection; - - for (SecIndexA::iterator itr = m_sections.begin(); itr != m_sections.end(); ++itr) - { - sSection = "[" + (*itr)->GetSectionName() + "]"; - - output << sSection << _CRLFA; - - for (KeyIndexA::iterator klitr = (*itr)->m_keys.begin(); klitr != (*itr)->m_keys.end(); ++klitr) - { - std::string sKey = (*klitr)->GetKeyName() + "=" + (*klitr)->GetValue(); - output << sKey << _CRLFA; - } - } -} - -bool CIniFileA::Save(const std::string& fileName) -{ - - std::ofstream output; - - output.open(fileName.c_str(), std::ios::binary); - - if (!output.is_open()) - return false; - - Save(output); - - output.close(); - return true; -} - - -void CIniFileA::Load(std::istream& input, bool bMerge) -{ - if (!bMerge) - RemoveAllSections(); - - CIniSectionA* pSection = NULL; - std::string sRead; - enum - { - KEY, - SECTION, - COMMENT, - OTHER - }; - - while (std::getline(input, sRead)) - { - - // Trim all whitespace on the left - LTrim(sRead); - // Trim any returns - RTrim(sRead, "\n\r"); - - if (!sRead.empty()) - { - auto nType = (sRead.find_first_of("[") == 0 && (sRead[sRead.find_last_not_of(" \t\r\n")] == ']')) ? SECTION : OTHER; - nType = ((nType == OTHER) && (sRead.find_first_of("=") != std::string::npos && sRead.find_first_of("=") > 0)) ? KEY : nType; - nType = ((nType == OTHER) && (sRead.find_first_of("#") == 0)) ? COMMENT : nType; - - switch (nType) - { - case SECTION: - pSection = AddSection(sRead.substr(1, sRead.size() - 2)); - break; - - case KEY: - { - // Check to ensure valid section... or drop the keys listed - if (pSection) - { - size_t iFind = sRead.find_first_of("="); - std::string sKey = sRead.substr(0, iFind); - std::string sValue = sRead.substr(iFind + 1); - CIniKeyA* pKey = pSection->AddKey(sKey); - if (pKey) - { - pKey->SetValue(sValue); - } - } - } - break; - case COMMENT: - break; - case OTHER: - break; - } - } - } -} - -bool CIniFileA::Load(const std::string& fileName, bool bMerge) -{ - std::ifstream input; - - input.open(fileName.c_str(), std::ios::binary); - - if (!input.is_open()) - return false; - - Load(input, bMerge); - - input.close(); - return true; -} - -const SecIndexA& CIniFileA::GetSections() const -{ - return m_sections; -} - - -CIniSectionA* CIniFileA::GetSection(std::string sSection) const -{ - Trim(sSection); - SecIndexA::const_iterator itr = _find_sec(sSection); - if (itr != m_sections.end()) - return *itr; - return NULL; -} - -CIniSectionA* CIniFileA::AddSection(std::string sSection) -{ - - Trim(sSection); - SecIndexA::const_iterator itr = _find_sec(sSection); - if (itr == m_sections.end()) - { - // Note constuctor doesn't trim the string so it is trimmed above - CIniSectionA* pSection = new CIniSectionA(this, sSection); - m_sections.insert(pSection); - return pSection; - } - else - return *itr; -} - - -std::string CIniFileA::GetKeyValue(const std::string& sSection, const std::string& sKey) const -{ - std::string sValue; - CIniSectionA* pSec = GetSection(sSection); - if (pSec) - { - CIniKeyA* pKey = pSec->GetKey(sKey); - if (pKey) - sValue = pKey->GetValue(); - } - return sValue; -} - -void CIniFileA::SetKeyValue(const std::string& sSection, const std::string& sKey, const std::string& sValue) -{ - CIniSectionA* pSec = AddSection(sSection); - if (pSec) - { - CIniKeyA* pKey = pSec->AddKey(sKey); - if (pKey) - pKey->SetValue(sValue); - } -} - - -void CIniFileA::RemoveSection(std::string sSection) -{ - Trim(sSection); - SecIndexA::iterator itr = _find_sec(sSection); - if (itr != m_sections.end()) - { - delete *itr; - m_sections.erase(itr); - } -} - -void CIniFileA::RemoveSection(CIniSectionA* pSection) -{ - // No trim since internal object not from user - SecIndexA::iterator itr = _find_sec(pSection->m_sSectionName); - if (itr != m_sections.end()) - { - delete *itr; - m_sections.erase(itr); - } -} - -void CIniFileA::RemoveAllSections() -{ - for (SecIndexA::iterator itr = m_sections.begin(); itr != m_sections.end(); ++itr) - { - delete *itr; - } - m_sections.clear(); -} - - -bool CIniFileA::RenameSection(const std::string& sSectionName, const std::string& sNewSectionName) -{ - // Note string trims are done in lower calls. - bool bRval = false; - CIniSectionA* pSec = GetSection(sSectionName); - if (pSec) - { - bRval = pSec->SetSectionName(sNewSectionName); - } - return bRval; -} - -bool CIniFileA::RenameKey(const std::string& sSectionName, const std::string& sKeyName, const std::string& sNewKeyName) -{ - // Note string trims are done in lower calls. - bool bRval = false; - CIniSectionA* pSec = GetSection(sSectionName); - if (pSec != NULL) - { - CIniKeyA* pKey = pSec->GetKey(sKeyName); - if (pKey != NULL) - bRval = pKey->SetKeyName(sNewKeyName); - } - return bRval; -} - -// Returns a constant iterator to a section by name, string is not trimmed -SecIndexA::const_iterator CIniFileA::_find_sec(const std::string& sSection) const -{ - CIniSectionA bogus(NULL, sSection); - return m_sections.find(&bogus); -} - -// Returns an iterator to a section by name, string is not trimmed -SecIndexA::iterator CIniFileA::_find_sec(const std::string& sSection) -{ - CIniSectionA bogus(NULL, sSection); - return m_sections.find(&bogus); -} - -// CIniFileA functions end here - -// CIniSectionA functions start here - -CIniSectionA::CIniSectionA(CIniFileA* pIniFile, const std::string& sSectionName) - : m_pIniFile(pIniFile) - , m_sSectionName(sSectionName) -{ -} - - -CIniSectionA::~CIniSectionA() -{ - RemoveAllKeys(); -} - -CIniKeyA* CIniSectionA::GetKey(std::string sKeyName) const -{ - Trim(sKeyName); - KeyIndexA::const_iterator itr = _find_key(sKeyName); - if (itr != m_keys.end()) - return *itr; - return NULL; -} - -void CIniSectionA::RemoveAllKeys() -{ - for (KeyIndexA::iterator itr = m_keys.begin(); itr != m_keys.end(); ++itr) - { - delete *itr; - } - m_keys.clear(); -} - -void CIniSectionA::RemoveKey(std::string sKey) -{ - Trim(sKey); - KeyIndexA::iterator itr = _find_key(sKey); - if (itr != m_keys.end()) - { - delete *itr; - m_keys.erase(itr); - } -} - -void CIniSectionA::RemoveKey(CIniKeyA* pKey) -{ - // No trim is done to improve efficiency since CIniKeyA* should already be trimmed - KeyIndexA::iterator itr = _find_key(pKey->m_sKeyName); - if (itr != m_keys.end()) - { - delete *itr; - m_keys.erase(itr); - } -} - -CIniKeyA* CIniSectionA::AddKey(std::string sKeyName) -{ - Trim(sKeyName); - KeyIndexA::const_iterator itr = _find_key(sKeyName); - if (itr == m_keys.end()) - { - // Note constuctor doesn't trim the string so it is trimmed above - CIniKeyA* pKey = new CIniKeyA(this, sKeyName); - m_keys.insert(pKey); - return pKey; - } - else - return *itr; -} - -bool CIniSectionA::SetSectionName(std::string sSectionName) -{ - Trim(sSectionName); - // Does this already exist. - if (m_pIniFile->_find_sec(sSectionName) == m_pIniFile->m_sections.end()) - { - - // Find the current section if one exists and remove it since we are renaming - SecIndexA::iterator itr = m_pIniFile->_find_sec(m_sSectionName); - - // Just to be safe make sure the old section exists - if (itr != m_pIniFile->m_sections.end()) - m_pIniFile->m_sections.erase(itr); - - // Change name prior to ensure tree balance - m_sSectionName = sSectionName; - - // Set the new map entry we know should not exist - m_pIniFile->m_sections.insert(this); - - return true; - } - else - { - return false; - } -} - -std::string CIniSectionA::GetSectionName() const -{ - return m_sSectionName; -} - -const KeyIndexA& CIniSectionA::GetKeys() const -{ - return m_keys; -} - -std::string CIniSectionA::GetKeyValue(const std::string& sKey) const -{ - std::string sValue; - CIniKeyA* pKey = GetKey(sKey); - if (pKey) - { - sValue = pKey->GetValue(); - } - return sValue; -} - -void CIniSectionA::SetKeyValue(const std::string& sKey, const std::string& sValue) -{ - CIniKeyA* pKey = AddKey(sKey); - if (pKey) - { - pKey->SetValue(sValue); - } -} - -// Returns a constant iterator to a key by name, string is not trimmed -KeyIndexA::const_iterator CIniSectionA::_find_key(const std::string& sKey) const -{ - CIniKeyA bogus(NULL, sKey); - return m_keys.find(&bogus); -} - -// Returns an iterator to a key by name, string is not trimmed -KeyIndexA::iterator CIniSectionA::_find_key(const std::string& sKey) -{ - CIniKeyA bogus(NULL, sKey); - return m_keys.find(&bogus); -} - -// CIniSectionA function end here - -// CIniKeyA Functions Start Here - -CIniKeyA::CIniKeyA(CIniSectionA* pSection, const std::string& sKeyName) - : m_pSection(pSection) - , m_sKeyName(sKeyName) -{ -} - - -CIniKeyA::~CIniKeyA() -{ -} - -void CIniKeyA::SetValue(const std::string& sValue) -{ - m_sValue = sValue; -} - -std::string CIniKeyA::GetValue() const -{ - return m_sValue; -} - -bool CIniKeyA::SetKeyName(std::string sKeyName) -{ - Trim(sKeyName); - - // Check for key name conflict - if (m_pSection->_find_key(sKeyName) == m_pSection->m_keys.end()) - { - KeyIndexA::iterator itr = m_pSection->_find_key(m_sKeyName); - - // Find the old map entry and remove it - if (itr != m_pSection->m_keys.end()) - m_pSection->m_keys.erase(itr); - - // Change name prior to ensure tree balance - m_sKeyName = sKeyName; - - // Make the new map entry - m_pSection->m_keys.insert(this); - return true; - } - else - { - return false; - } -} - -std::string CIniKeyA::GetKeyName() const -{ - return m_sKeyName; -} - -// End of CIniKeyA Functions - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// WIDE FUNCTIONS HERE -// -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Helper Functions -void RTrim(std::wstring& str, const std::wstring& chars = L" \t") -{ - str.erase(str.find_last_not_of(chars) + 1); -} - -void LTrim(std::wstring& str, const std::wstring& chars = L" \t") -{ - str.erase(0, str.find_first_not_of(chars)); -} - -void Trim(std::wstring& str, const std::wstring& chars = L" \t") -{ - str.erase(str.find_last_not_of(chars) + 1); - str.erase(0, str.find_first_not_of(chars)); -} - -// Stream Helpers -std::wostream& operator<<(std::wostream& output, CIniFileW& obj) -{ - obj.Save(output); - return output; -} - -std::wistream& operator>>(std::wistream& input, CIniFileW& obj) -{ - obj.Load(input); - return input; -} - -std::wistream& operator>>(std::wistream& input, CIniMergeW merger) -{ - return merger(input); -} - -CIniFileW::CIniFileW() -{ -} - -CIniFileW::~CIniFileW() -{ - RemoveAllSections(); -} - -const wchar_t* const CIniFileW::LF = _CRLFW; - -void CIniFileW::Save(std::wostream& output) -{ - std::wstring sSection; - - for (SecIndexW::iterator itr = m_sections.begin(); itr != m_sections.end(); ++itr) - { - sSection = L"[" + (*itr)->GetSectionName() + L"]"; - - output << sSection << _CRLFA; - - for (KeyIndexW::iterator klitr = (*itr)->m_keys.begin(); klitr != (*itr)->m_keys.end(); ++klitr) - { - std::wstring sKey = (*klitr)->GetKeyName() + L"=" + (*klitr)->GetValue(); - output << sKey << _CRLFA; - } - } -} - -bool CIniFileW::Save(const std::wstring& fileName) -{ - - std::wofstream output; - -#if defined(_MSC_VER) && (_MSC_VER >= 1300) - output.open(fileName.c_str(), std::ios::binary); -#else - output.open(wstr_to_str(fileName).c_str(), std::ios::binary); -#endif - - if (!output.is_open()) - return false; - - Save(output); - - output.close(); - return true; -} - - -void CIniFileW::Load(std::wistream& input, bool bMerge) -{ - if (!bMerge) - RemoveAllSections(); - - CIniSectionW* pSection = NULL; - std::wstring sRead; - enum - { - KEY, - SECTION, - COMMENT, - OTHER - }; - - while (std::getline(input, sRead)) - { - - // Trim all whitespace on the left - LTrim(sRead); - // Trim any returns - RTrim(sRead, L"\n\r"); - - if (!sRead.empty()) - { - auto nType = (sRead.find_first_of(L"[") == 0 && (sRead[sRead.find_last_not_of(L" \t\r\n")] == L']')) ? SECTION : OTHER; - nType = ((nType == OTHER) && (sRead.find_first_of(L"=") != std::wstring::npos && sRead.find_first_of(L"=") > 0)) ? KEY : nType; - nType = ((nType == OTHER) && (sRead.find_first_of(L"#") == 0)) ? COMMENT : nType; - - switch (nType) - { - case SECTION: - pSection = AddSection(sRead.substr(1, sRead.size() - 2)); - break; - - case KEY: - { - // Check to ensure valid section... or drop the keys listed - if (pSection) - { - size_t iFind = sRead.find_first_of(L"="); - std::wstring sKey = sRead.substr(0, iFind); - std::wstring sValue = sRead.substr(iFind + 1); - CIniKeyW* pKey = pSection->AddKey(sKey); - if (pKey) - { - pKey->SetValue(sValue); - } - } - } - break; - case COMMENT: - break; - case OTHER: - break; - } - } - } -} - -bool CIniFileW::Load(const std::wstring& fileName, bool bMerge) -{ - - std::wifstream input; - -#if defined(_MSC_VER) && (_MSC_VER >= 1300) - input.open(fileName.c_str(), std::ios::binary); -#else - input.open(wstr_to_str(fileName).c_str(), std::ios::binary); -#endif - - if (!input.is_open()) - return false; - - Load(input, bMerge); - - input.close(); - return true; -} - -const SecIndexW& CIniFileW::GetSections() const -{ - return m_sections; -} - - -CIniSectionW* CIniFileW::GetSection(std::wstring sSection) const -{ - Trim(sSection); - SecIndexW::const_iterator itr = _find_sec(sSection); - if (itr != m_sections.end()) - return *itr; - return NULL; -} - -CIniSectionW* CIniFileW::AddSection(std::wstring sSection) -{ - Trim(sSection); - SecIndexW::const_iterator itr = _find_sec(sSection); - if (itr == m_sections.end()) - { - // Note constuctor doesn't trim the string so it is trimmed above - CIniSectionW* pSection = new CIniSectionW(this, sSection); - m_sections.insert(pSection); - return pSection; - } - else - return *itr; -} - - -std::wstring CIniFileW::GetKeyValue(const std::wstring& sSection, const std::wstring& sKey) const -{ - std::wstring sValue; - CIniSectionW* pSec = GetSection(sSection); - if (pSec) - { - CIniKeyW* pKey = pSec->GetKey(sKey); - if (pKey) - sValue = pKey->GetValue(); - } - return sValue; -} - -void CIniFileW::SetKeyValue(const std::wstring& sSection, const std::wstring& sKey, const std::wstring& sValue) -{ - CIniSectionW* pSec = AddSection(sSection); - if (pSec) - { - CIniKeyW* pKey = pSec->AddKey(sKey); - if (pKey) - pKey->SetValue(sValue); - } -} - - -void CIniFileW::RemoveSection(std::wstring sSection) -{ - Trim(sSection); - SecIndexW::iterator itr = _find_sec(sSection); - if (itr != m_sections.end()) - { - delete *itr; - m_sections.erase(itr); - } -} - -void CIniFileW::RemoveSection(CIniSectionW* pSection) -{ - // No trim since internal object not from user - SecIndexW::iterator itr = _find_sec(pSection->m_sSectionName); - if (itr != m_sections.end()) - { - delete *itr; - m_sections.erase(itr); - } -} - -void CIniFileW::RemoveAllSections() -{ - for (SecIndexW::iterator itr = m_sections.begin(); itr != m_sections.end(); ++itr) - { - delete *itr; - } - m_sections.clear(); -} - - -bool CIniFileW::RenameSection(const std::wstring& sSectionName, const std::wstring& sNewSectionName) -{ - // Note string trims are done in lower calls. - bool bRval = false; - CIniSectionW* pSec = GetSection(sSectionName); - if (pSec) - { - bRval = pSec->SetSectionName(sNewSectionName); - } - return bRval; -} - -bool CIniFileW::RenameKey(const std::wstring& sSectionName, const std::wstring& sKeyName, const std::wstring& sNewKeyName) -{ - // Note string trims are done in lower calls. - bool bRval = false; - CIniSectionW* pSec = GetSection(sSectionName); - if (pSec != NULL) - { - CIniKeyW* pKey = pSec->GetKey(sKeyName); - if (pKey != NULL) - bRval = pKey->SetKeyName(sNewKeyName); - } - return bRval; -} - -// Returns a constant iterator to a section by name, string is not trimmed -SecIndexW::const_iterator CIniFileW::_find_sec(const std::wstring& sSection) const -{ - CIniSectionW bogus(NULL, sSection); - return m_sections.find(&bogus); -} - -// Returns an iterator to a section by name, string is not trimmed -SecIndexW::iterator CIniFileW::_find_sec(const std::wstring& sSection) -{ - CIniSectionW bogus(NULL, sSection); - return m_sections.find(&bogus); -} - -// CIniFileW functions end here - -// CIniSectionW functions start here - -CIniSectionW::CIniSectionW(CIniFileW* pIniFile, const std::wstring& sSectionName) - : m_pIniFile(pIniFile) - , m_sSectionName(sSectionName) -{ -} - - -CIniSectionW::~CIniSectionW() -{ - RemoveAllKeys(); -} - -CIniKeyW* CIniSectionW::GetKey(std::wstring sKeyName) const -{ - Trim(sKeyName); - KeyIndexW::const_iterator itr = _find_key(sKeyName); - if (itr != m_keys.end()) - return *itr; - return NULL; -} - -void CIniSectionW::RemoveAllKeys() -{ - for (KeyIndexW::iterator itr = m_keys.begin(); itr != m_keys.end(); ++itr) - { - delete *itr; - } - m_keys.clear(); -} - -void CIniSectionW::RemoveKey(std::wstring sKey) -{ - Trim(sKey); - KeyIndexW::iterator itr = _find_key(sKey); - if (itr != m_keys.end()) - { - delete *itr; - m_keys.erase(itr); - } -} - -void CIniSectionW::RemoveKey(CIniKeyW* pKey) -{ - // No trim is done to improve efficiency since CIniKeyW* should already be trimmed - KeyIndexW::iterator itr = _find_key(pKey->m_sKeyName); - if (itr != m_keys.end()) - { - delete *itr; - m_keys.erase(itr); - } -} - -CIniKeyW* CIniSectionW::AddKey(std::wstring sKeyName) -{ - Trim(sKeyName); - KeyIndexW::const_iterator itr = _find_key(sKeyName); - if (itr == m_keys.end()) - { - // Note constuctor doesn't trim the string so it is trimmed above - CIniKeyW* pKey = new CIniKeyW(this, sKeyName); - m_keys.insert(pKey); - return pKey; - } - else - return *itr; -} - -bool CIniSectionW::SetSectionName(std::wstring sSectionName) -{ - Trim(sSectionName); - // Does this already exist. - if (m_pIniFile->_find_sec(sSectionName) == m_pIniFile->m_sections.end()) - { - // Find the current section if one exists and remove it since we are renaming - SecIndexW::iterator itr = m_pIniFile->_find_sec(m_sSectionName); - - // Just to be safe make sure the old section exists - if (itr != m_pIniFile->m_sections.end()) - m_pIniFile->m_sections.erase(itr); - - // Change name prior to ensure tree balance - m_sSectionName = sSectionName; - - // Set the new map entry we know should not exist - m_pIniFile->m_sections.insert(this); - - return true; - } - else - { - return false; - } -} - -std::wstring CIniSectionW::GetSectionName() const -{ - return m_sSectionName; -} - -const KeyIndexW& CIniSectionW::GetKeys() const -{ - return m_keys; -} - -std::wstring CIniSectionW::GetKeyValue(const std::wstring& sKey) const -{ - std::wstring sValue; - CIniKeyW* pKey = GetKey(sKey); - if (pKey) - { - sValue = pKey->GetValue(); - } - return sValue; -} - -void CIniSectionW::SetKeyValue(const std::wstring& sKey, const std::wstring& sValue) -{ - CIniKeyW* pKey = AddKey(sKey); - if (pKey) - { - pKey->SetValue(sValue); - } -} - -// Returns a constant iterator to a key by name, string is not trimmed -KeyIndexW::const_iterator CIniSectionW::_find_key(const std::wstring& sKey) const -{ - CIniKeyW bogus(NULL, sKey); - return m_keys.find(&bogus); -} - -// Returns an iterator to a key by name, string is not trimmed -KeyIndexW::iterator CIniSectionW::_find_key(const std::wstring& sKey) -{ - CIniKeyW bogus(NULL, sKey); - return m_keys.find(&bogus); -} - -// CIniSectionW function end here - -// CIniKeyW Functions Start Here - -CIniKeyW::CIniKeyW(CIniSectionW* pSection, const std::wstring& sKeyName) - : m_pSection(pSection) - , m_sKeyName(sKeyName) -{ -} - - -CIniKeyW::~CIniKeyW() -{ -} - -void CIniKeyW::SetValue(const std::wstring& sValue) -{ - m_sValue = sValue; -} - -std::wstring CIniKeyW::GetValue() const -{ - return m_sValue; -} - -bool CIniKeyW::SetKeyName(std::wstring sKeyName) -{ - Trim(sKeyName); - - // Check for key name conflict - if (m_pSection->_find_key(sKeyName) == m_pSection->m_keys.end()) - { - KeyIndexW::iterator itr = m_pSection->_find_key(m_sKeyName); - - // Find the old map entry and remove it - if (itr != m_pSection->m_keys.end()) - m_pSection->m_keys.erase(itr); - - // Change name prior to ensure tree balance - m_sKeyName = sKeyName; - - // Make the new map entry - m_pSection->m_keys.insert(this); - return true; - } - else - { - return false; - } -} - -std::wstring CIniKeyW::GetKeyName() const -{ - return m_sKeyName; -} - -// End of CIniKeyW Functions diff --git a/pcsx2/USB/shared/inifile_usb.h b/pcsx2/USB/shared/inifile_usb.h deleted file mode 100644 index a21587e5cf..0000000000 --- a/pcsx2/USB/shared/inifile_usb.h +++ /dev/null @@ -1,568 +0,0 @@ -/******************************************************************************************************************************* - Programmer: Ludvik Jerabek - Date: June 15th, 2009 - - Defined Classed: CIniFileW CIniFileA - - Purpose: C++ Inifile Reader\Writer. Uses std::set and stdext::hash_set to implement an efficient ini object. - - Summary: This is a total re-write of the original CIniFile class written in 2006. Originally the data structures - underlying the CIniFile object were std::list which was extreamly inefficient when dealing with huge ini files. - - - Note: The class currently supports std::wstring and std::string. The typedef CIniFile is based on the whether of no - _UNICODE is defined. If _UNICODE is define in your project CIniFile is a CIniFileW if _UNICODE is not defined - then CIniFile is a CIniFileA object. - - Defines: - - _TRACE_CINIFILE - If defined enables call tracing to standard output - _UNICODE - If defined the CIniFile will be defined as CIniFileW instead of CIniFileA - _FORCE_UNIX_LINEFEED - If defined when _WIN32 is defined (WINDOWS) the default linefeed CRLF is overridden to CR - _FORCE_WINDOWS_LINEFEED - If defined when _WIN32 is not defined (*NIX) the default linefeed CR is overridden to CRLF - - Updates: - - 12\01\2005 - Initial MFC Release. - 01\12\2006 - Ported to Ansi C++ Non-MFC. - 06\16\2009 - Added support for different linefeed types, resolved issues around reading different types of linefeeds. - 06\17\2009 - Added support for wide characters. - 06\21\2009 - Re-written to use std::map. - 07\02\2009 - Removed MFC version. Since Ansi version works in MFC ( Examples provided for download ). - 07\03\2009 - Added support for VS6. - 07\03\2009 - Fixed issue with SecIndexA \ SecIndexW. Were not named specific to the encoding may have caused issues. - 07\03\2009 - Fixed GetKeys and GetSections functions to return const ref v.s. copy of data. - 07\14\2009 - Fixed Load() whitespace preservation on key value. - 09\21\2009 - Fixed removing all the sections and keys, replaced empty() with clear() - 09\22\2009 - Added overloaded Load() and Save() to read\write streams - 09\23\2009 - Added operators for << and >> to be used with streams - 09\24\2009 - Added merge option to Load() - 09\25\2009 - Added CIniMerge for use with << and >> - 09\27\2009 - Moved CIniMerge into CIniFile, fixed issue with VC6 CIniFile::CR - 12\29\2010 - Reduced key storage redundancy by using std::set instead of std::map - 12\29\2010 - Reduced number of pass by value methods to reduce deep copy (std::string to const std::string&) - 05\07\2011 - Fixed MSC_VER to _MSC_VER - 05\07\2011 - Fixed OTHER file parse detection issue - -*******************************************************************************************************************************/ -#ifndef __CINIFILE_H_ -#define __CINIFILE_H_ - -#ifdef _WIN32 -// Prevent compile time warnings for deprecation -#if !defined(_CRT_SECURE_NO_DEPRECATE) -#define _CRT_SECURE_NO_DEPRECATE -#endif -#endif - -#include -#include -#include -#include -#include - -#define INI_TOKEN_A_ANSI "\a" // I.E. Item1;Item2;Item3 - '\a' used in place of ';' -#define INI_TOKEN_B_ANSI "\b" // I.E. Item1,Item1b;Item2,Item2b;Item3,Item3b - '\b' used in place of ',' -#define INI_EMPTY_ANSI "*" // Used to indicate empty value in token string. I.E. *;Item2;*;Item3; - -class CIniFileA -{ -public: - static const char* const LF; - -public: - CIniFileA(); - ~CIniFileA(); - - // Used to save the data back to the file or your choice - bool Save(const std::string& fileName); - - // Save data to an output stream - void Save(std::ostream& output); - - // Loads the Reads the data in the ini file into the IniFile object - bool Load(const std::string& fileName, bool bMerge = false); - - // Load data from an input stream - void Load(std::istream& input, bool bMerge = false); - -public: - class CIniMergeA - { - public: - explicit CIniMergeA(CIniFileA& ini) - : _ini(ini) - { - } - std::istream& operator()(std::istream& input) const - { - _ini.Load(input, true); - return input; - } - - private: - CIniFileA& _ini; - }; - -public: -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - struct ci_less_a; -#endif -#endif - class CIniSectionA - { - friend class CIniFileA; // Allow CIniFileA to create sections -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - friend struct ci_less_a; - -#endif -#endif - public: -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - struct ci_less_a; -#endif -#endif - class CIniKeyA - { - friend class CIniSectionA; // Allow CIniSectionA to create keys -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - friend struct ci_less_a; -#endif -#endif - private: // CIniFileA acts as a class factory for CIniSectionA Objects - CIniKeyA(CIniSectionA* pSection, const std::string& sKeyName); - CIniKeyA(const CIniKeyA&); // No Copy - CIniKeyA& operator=(const CIniKeyA&); // No Copy - ~CIniKeyA(); - - public: - // Sets the value of the key - void SetValue(const std::string& sValue); - // Returns the value of the key - std::string GetValue() const; - // Sets the key name, returns true on success, fails if the section - // name sKeyName already exists - bool SetKeyName(std::string sKeyName); - // Returns the name of the Key - std::string GetKeyName() const; - - private: - // Pointer to the parent CIniSectionA - CIniSectionA* m_pSection; - // Name of the Key - std::string m_sKeyName; - // Value associated - std::string m_sValue; - }; // End of CIniKeyA - // Typedef of set of CIniKeyA pointers - struct ci_less_a - { - bool operator()(const CIniKeyA* s1, const CIniKeyA* s2) const - { -#ifndef _WIN32 - return strcasecmp(s1->m_sKeyName.c_str(), s2->m_sKeyName.c_str()) < 0; -#else - return _stricmp(s1->m_sKeyName.c_str(), s2->m_sKeyName.c_str()) < 0; -#endif - } - }; - - typedef std::set KeyIndexA; - -#ifdef _WIN32 - // Added for VC6 Support -#if defined(_MSC_VER) && (_MSC_VER >= 1200) && (_MSC_VER < 1300) - friend class CIniKeyA; -#endif -#endif - private: // CIniSectionA acts as a class factory for CIniKeyA Objects - CIniSectionA(CIniFileA* pIniFile, const std::string& sSectionName); - CIniSectionA(const CIniSectionA&); // No Copy - CIniSectionA& operator=(const CIniSectionA&); // No Copy - ~CIniSectionA(); - - public: - // Adds a key to the CIniSectionA object, returns a CIniKeyA pointer to the new or existing object - CIniKeyA* AddKey(std::string sKeyName); - // Removes a single key by pointer - void RemoveKey(CIniKeyA* pKey); - // Removes a single key by string - void RemoveKey(std::string sKey); - // Removes all the keys in the section - void RemoveAllKeys(); - // Returns a CIniKeyA pointer to the key by name, NULL if it was not found - CIniKeyA* GetKey(std::string sKeyName) const; - // Returns all keys in the section by KeyIndex only to be used for enumeration - const KeyIndexA& GetKeys() const; - // Returns a KeyValue at a certain section - std::string GetKeyValue(const std::string& sKey) const; - // Sets a KeyValuePair at a certain section - void SetKeyValue(const std::string& sKey, const std::string& sValue); - // Sets the section name, returns true on success, fails if the section - // name sSectionName already exists - bool SetSectionName(std::string sSectionName); - // Returns the section name - std::string GetSectionName() const; - - private: - KeyIndexA::const_iterator _find_key(const std::string& sKeyName) const; - KeyIndexA::iterator _find_key(const std::string& sKeyName); - - private: - // CIniFileA pointer back to the object that instanciated the section - CIniFileA* m_pIniFile; - // Name of the section - std::string m_sSectionName; - // List of CIniKeyA pointers ( Keys in the section ) - KeyIndexA m_keys; - }; // End of CIniSectionA - // Typedef of a List of CIniSectionA pointers - struct ci_less_a - { - bool operator()(const CIniSectionA* s1, const CIniSectionA* s2) const - { -#ifndef _WIN32 - return strcasecmp(s1->m_sSectionName.c_str(), s2->m_sSectionName.c_str()) < 0; -#else - return _stricmp(s1->m_sSectionName.c_str(), s2->m_sSectionName.c_str()) < 0; -#endif - } - }; - - typedef std::set SecIndexA; - -#ifdef _WIN32 - // Added for VC6 Support -#if defined(_MSC_VER) && (_MSC_VER >= 1200) && (_MSC_VER < 1300) - friend class CIniSectionA; -#endif -#endif -public: - // Adds a section to the CIniFileA object, returns a CIniFileA pointer to the new or existing object - CIniSectionA* AddSection(std::string sSection); - // Removes section by pointer - void RemoveSection(CIniSectionA* pSection); - // Removes a section by its name sSection - void RemoveSection(std::string sSection); - // Removes all existing sections - void RemoveAllSections(); - // Returns a CIniSectionA* to the section by name, NULL if it was not found - CIniSectionA* GetSection(std::string sSection) const; - // Returns all sections in the inifile by SecIndex, only to be used for enumeration (DO NOT KEEP THE REF OR TRY TO DELETE STUFF!) - const SecIndexA& GetSections() const; - // Returns a KeyValue at a certain section - std::string GetKeyValue(const std::string& sSection, const std::string& sKey) const; - // Sets a KeyValuePair at a certain section - void SetKeyValue(const std::string& sSection, const std::string& sKey, const std::string& sValue); - // Renames an existing section returns true on success, false if the section didn't exist or there was another section with the same sNewSectionName - bool RenameSection(const std::string& sSectionName, const std::string& sNewSectionName); - // Renames an existing key returns true on success, false if the key didn't exist or there was another section with the same sNewSectionName - bool RenameKey(const std::string& sSectionName, const std::string& sKeyName, const std::string& sNewKeyName); - -private: - SecIndexA::const_iterator _find_sec(const std::string& sSection) const; - SecIndexA::iterator _find_sec(const std::string& sSection); - -private: - CIniFileA(const CIniFileA&); // No Copy - CIniFileA& operator=(const CIniFileA&); // No Copy - // List of CIniSectionA pointers ( List of sections in the class ) - SecIndexA m_sections; -}; // End of CIniFileA - -// Basic typedefs for ease of use -typedef CIniFileA::CIniMergeA CIniMergeA; -typedef CIniFileA::CIniSectionA CIniSectionA; -typedef CIniSectionA::CIniKeyA CIniKeyA; - -// Pointers -typedef CIniFileA* PCINIA; -typedef CIniKeyA* PCINIKEYA; -typedef CIniSectionA* PCINISECA; - -// Map Types -typedef CIniSectionA::KeyIndexA KeyIndexA; -typedef CIniFileA::SecIndexA SecIndexA; - -std::ostream& operator<<(std::ostream& output, CIniFileA& obj); -std::istream& operator>>(std::istream& input, CIniFileA& obj); -std::istream& operator>>(std::istream& input, CIniMergeA merger); - -// Unicode Class Definition - -#define INI_TOKEN_A_UNICODE L"\a" // I.E. Item1;Item2;Item3 - '\a' used in place of ';' -#define INI_TOKEN_B_UNICODE L"\b" // I.E. Item1,Item1b;Item2,Item2b;Item3,Item3b - '\b' used in place of ',' -#define INI_EMPTY_UNICODE L"*" // Used to indicate empty value in token string. I.E. *;Item2;*;Item3; - -class CIniFileW -{ -public: - static const wchar_t* const LF; - -public: - CIniFileW(); - ~CIniFileW(); - - // Used to save the data back to the file or your choice - bool Save(const std::wstring& fileName); - - // Save data to an output stream - void Save(std::wostream& output); - - // Loads the Reads the data in the ini file into the IniFile object - bool Load(const std::wstring& fileName, bool bMerge = false); - - // Load data from an input stream - void Load(std::wistream& input, bool bMerge = false); - -public: - class CIniMergeW - { - public: - explicit CIniMergeW(CIniFileW& ini) - : _ini(ini) - { - } - std::wistream& operator()(std::wistream& input) const - { - _ini.Load(input, true); - return input; - } - - private: - CIniFileW& _ini; - }; - -public: -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - struct ci_less_w; -#endif -#endif - class CIniSectionW - { - friend class CIniFileW; // Allow CIniFileW to create sections -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - friend struct ci_less_w; -#endif -#endif - public: -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - struct ci_less_w; -#endif -#endif - class CIniKeyW - { - friend class CIniSectionW; // Allow CIniSectionW to create keys -#ifdef _WIN32 - // Added for versions earlier than VS2008 -#if defined(_MSC_VER) && (_MSC_VER <= 1400) - friend struct ci_less_w; -#endif -#endif - private: // CIniFileW acts as a class factory for CIniSectionW Objects - CIniKeyW(CIniSectionW* pSection, const std::wstring& sKeyName); - CIniKeyW(const CIniKeyW&); // No Copy - CIniKeyW& operator=(const CIniKeyW&); // No Copy - ~CIniKeyW(); - - public: - // Sets the value of the key - void SetValue(const std::wstring& sValue); - // Returns the value of the key - std::wstring GetValue() const; - // Sets the key name, returns true on success, fails if the section - // name sKeyName already exists - bool SetKeyName(std::wstring sKeyName); - // Returns the name of the Key - std::wstring GetKeyName() const; - - private: - // Pointer to the parent CIniSectionW - CIniSectionW* m_pSection; - // Name of the Key - std::wstring m_sKeyName; - // Value associated - std::wstring m_sValue; - }; // End of CIniKeyW - // Typedef of set of CIniKeyW pointers - struct ci_less_w - { - bool operator()(const CIniKeyW* s1, const CIniKeyW* s2) const - { -#ifndef _WIN32 - return wcscasecmp(s1->m_sKeyName.c_str(), s2->m_sKeyName.c_str()) < 0; -#else - return _wcsicmp(s1->m_sKeyName.c_str(), s2->m_sKeyName.c_str()) < 0; -#endif - } - }; - - typedef std::set KeyIndexW; - -#ifdef _WIN32 - // Added for VC6 Support -#if defined(_MSC_VER) && (_MSC_VER >= 1200) && (_MSC_VER < 1300) - friend class CIniKeyW; -#endif -#endif - private: // CIniSectionW acts as a class factory for CIniKeyW Objects - CIniSectionW(CIniFileW* pIniFile, const std::wstring& sSectionName); - CIniSectionW(const CIniSectionW&); // No Copy - CIniSectionW& operator=(const CIniSectionW&); // No Copy - ~CIniSectionW(); - - public: - // Adds a key to the CIniSectionW object, returns a CIniKeyW pointer to the new or existing object - CIniKeyW* AddKey(std::wstring sKeyName); - // Removes a single key by pointer - void RemoveKey(CIniKeyW* pKey); - // Removes a single key by string - void RemoveKey(std::wstring sKey); - // Removes all the keys in the section - void RemoveAllKeys(); - // Returns a CIniKeyW pointer to the key by name, NULL if it was not found - CIniKeyW* GetKey(std::wstring sKeyName) const; - // Returns all keys in the section by KeyIndex only to be used for enumeration - const KeyIndexW& GetKeys() const; - // Returns a KeyValue at a certain section - std::wstring GetKeyValue(const std::wstring& sKey) const; - // Sets a KeyValuePair at a certain section - void SetKeyValue(const std::wstring& sKey, const std::wstring& sValue); - // Sets the section name, returns true on success, fails if the section - // name sSectionName already exists - bool SetSectionName(std::wstring sSectionName); - // Returns the section name - std::wstring GetSectionName() const; - - private: - KeyIndexW::const_iterator _find_key(const std::wstring& sKeyName) const; - KeyIndexW::iterator _find_key(const std::wstring& sKeyName); - - private: - // CIniFileW pointer back to the object that instanciated the section - CIniFileW* m_pIniFile; - // Name of the section - std::wstring m_sSectionName; - // List of CIniKeyW pointers ( Keys in the section ) - KeyIndexW m_keys; - }; // End of CIniSectionW - // Typedef of a List of CIniSectionW pointers - struct ci_less_w - { - bool operator()(const CIniSectionW* s1, const CIniSectionW* s2) const - { -#ifndef _WIN32 - return wcscasecmp(s1->m_sSectionName.c_str(), s2->m_sSectionName.c_str()) < 0; -#else - return _wcsicmp(s1->m_sSectionName.c_str(), s2->m_sSectionName.c_str()) < 0; -#endif - } - }; - - typedef std::set SecIndexW; - -#ifdef _WIN32 - // Added for VC6 Support -#if defined(_MSC_VER) && (_MSC_VER >= 1200) && (_MSC_VER < 1300) - friend class CIniSectionW; -#endif -#endif -public: - // Adds a section to the CIniFileW object, returns a CIniFileW pointer to the new or existing object - CIniSectionW* AddSection(std::wstring sSection); - // Removes section by pointer - void RemoveSection(CIniSectionW* pSection); - // Removes a section by its name sSection - void RemoveSection(std::wstring sSection); - // Removes all existing sections - void RemoveAllSections(); - // Returns a CIniSectionW* to the section by name, NULL if it was not found - CIniSectionW* GetSection(std::wstring sSection) const; - // Returns all sections in the inifile by SecIndex, only to be used for enumeration (DO NOT KEEP THE REF OR TRY TO DELETE STUFF!) - const SecIndexW& GetSections() const; - // Returns a KeyValue at a certain section - std::wstring GetKeyValue(const std::wstring& sSection, const std::wstring& sKey) const; - // Sets a KeyValuePair at a certain section - void SetKeyValue(const std::wstring& sSection, const std::wstring& sKey, const std::wstring& sValue); - // Renames an existing section returns true on success, false if the section didn't exist or there was another section with the same sNewSectionName - bool RenameSection(const std::wstring& sSectionName, const std::wstring& sNewSectionName); - // Renames an existing key returns true on success, false if the key didn't exist or there was another section with the same sNewSectionName - bool RenameKey(const std::wstring& sSectionName, const std::wstring& sKeyName, const std::wstring& sNewKeyName); - -private: - SecIndexW::const_iterator _find_sec(const std::wstring& sSection) const; - SecIndexW::iterator _find_sec(const std::wstring& sSection); - -private: - CIniFileW(const CIniFileW&); // No Copy - CIniFileW& operator=(const CIniFileW&); // No Copy - // List of CIniSectionW pointers ( List of sections in the class ) - SecIndexW m_sections; -}; // End of CIniFileW - -// Basic typedefs for ease of use -typedef CIniFileW::CIniMergeW CIniMergeW; -typedef CIniFileW::CIniSectionW CIniSectionW; -typedef CIniSectionW::CIniKeyW CIniKeyW; - -// Pointers -typedef CIniFileW* PCINIW; -typedef CIniKeyW* PCINIKEYW; -typedef CIniSectionW* PCINISECW; - -// Map Types -typedef CIniSectionW::KeyIndexW KeyIndexW; -typedef CIniFileW::SecIndexW SecIndexW; - -std::wostream& operator<<(std::wostream& output, CIniFileW& obj); -std::wistream& operator>>(std::wistream& input, CIniFileW& obj); -std::wistream& operator>>(std::wistream& input, CIniMergeW merger); - -// Additional defines -#ifdef _UNICODE -#define INI_TOKEN_A INI_TOKEN_UNICODE -#define INI_TOKEN_B INI_TOKEN_UNICODE -#define INI_EMPTY INI_EMPTY_UNICODE -typedef CIniMergeW CIniMerge; -typedef CIniFileW CIniFile; -typedef CIniSectionW CIniSection; -typedef CIniKeyW CIniKey; -typedef PCINIW PCINI; -typedef PCINIKEYW PCINIKEY; -typedef PCINISECW PCINISEC; -typedef KeyIndexW KeyIndex; -typedef SecIndexW SecIndex; -#else -#define INI_TOKEN_A INI_TOKEN_ANSI -#define INI_TOKEN_B INI_TOKEN_ANSI -#define INI_EMPTY INI_EMPTY_ANSI -typedef CIniMergeA CIniMerge; -typedef CIniFileA CIniFile; -typedef CIniSectionA CIniSection; -typedef CIniKeyA CIniKey; -typedef PCINIA PCINI; -typedef PCINIKEYA PCINIKEY; -typedef PCINISECA PCINISEC; -typedef KeyIndexA KeyIndex; -typedef SecIndexA SecIndex; -#endif - - -std::wstring str_to_wstr(const std::string& arg); -std::string wstr_to_str(const std::wstring& arg); - -#endif diff --git a/pcsx2/USB/shared/rawinput_usb.cpp b/pcsx2/USB/shared/rawinput_usb.cpp deleted file mode 100644 index cd589c8eb6..0000000000 --- a/pcsx2/USB/shared/rawinput_usb.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "rawinput_usb.h" -#include -#include -#include -#include -#include "USB/platcompat.h" -#include "PAD/Windows/WndProcEater.h" - -extern HINSTANCE hInst; - -namespace shared -{ - namespace rawinput - { - - static std::vector callbacks; - - bool inited = false; - bool skipInput = false; - std::mutex cb_mutex; - - void RegisterCallback(ParseRawInputCB* cb) - { - std::scoped_lock lk(cb_mutex); - if (cb && std::find(callbacks.begin(), callbacks.end(), cb) == callbacks.end()) - callbacks.push_back(cb); - } - - void UnregisterCallback(ParseRawInputCB* cb) - { - std::scoped_lock lk(cb_mutex); - auto it = std::find(callbacks.begin(), callbacks.end(), cb); - if (it != callbacks.end()) - callbacks.erase(it); - } - - static POINT origCursorPos; - static POINT center; - static bool cursorCaptured = false; - - static void WindowResized(HWND hWnd) - { - RECT r; - GetWindowRect(hWnd, &r); - ClipCursor(&r); - center.x = (r.left + r.right) / 2; - center.y = (r.top + r.bottom) / 2; - SetCursorPos(center.x, center.y); - } - - static void CursorCapture(HWND hWnd) - { - Console.WriteLn("Capture cursor\n"); - SetCapture(hWnd); - ShowCursor(0); - - GetCursorPos(&origCursorPos); - - RECT r; - GetWindowRect(hWnd, &r); - ClipCursor(&r); - center.x = (r.left + r.right) / 2; - center.y = (r.top + r.bottom) / 2; - SetCursorPos(center.x, center.y); - cursorCaptured = true; - } - - static void CursorRelease() - { - Console.WriteLn("Release cursor\n"); - if (cursorCaptured) - { - ClipCursor(0); - ReleaseCapture(); - ShowCursor(1); - SetCursorPos(origCursorPos.x, origCursorPos.y); - cursorCaptured = false; - } - } - - static void ToggleCursor(HWND hWnd, RAWKEYBOARD& k) - { - static bool shiftDown = false; - - if (k.VKey == VK_SHIFT || k.VKey == VK_LSHIFT || k.VKey == VK_RSHIFT) - shiftDown = !(k.Flags & RI_KEY_BREAK); - - if (shiftDown && k.VKey == VK_F11 && !k.Flags) - { - if (!cursorCaptured) - CursorCapture(hWnd); - else - CursorRelease(); - } - } - - static int RegisterRaw(HWND hWnd) - { - RAWINPUTDEVICE Rid[4]; - Rid[0].usUsagePage = 0x01; - Rid[0].usUsage = HID_USAGE_GENERIC_GAMEPAD; - Rid[0].dwFlags = hWnd ? RIDEV_INPUTSINK : RIDEV_REMOVE; // adds game pad - Rid[0].hwndTarget = hWnd; - - Rid[1].usUsagePage = 0x01; - Rid[1].usUsage = HID_USAGE_GENERIC_JOYSTICK; - Rid[1].dwFlags = hWnd ? RIDEV_INPUTSINK : RIDEV_REMOVE; // adds joystick - Rid[1].hwndTarget = hWnd; - - Rid[2].usUsagePage = 0x01; - Rid[2].usUsage = HID_USAGE_GENERIC_KEYBOARD; - Rid[2].dwFlags = hWnd ? RIDEV_INPUTSINK : RIDEV_REMOVE; // | RIDEV_NOLEGACY; // adds HID keyboard //and also !ignores legacy keyboard messages - Rid[2].hwndTarget = hWnd; - - Rid[3].usUsagePage = 0x01; - Rid[3].usUsage = HID_USAGE_GENERIC_MOUSE; - Rid[3].dwFlags = hWnd ? RIDEV_INPUTSINK : RIDEV_REMOVE; - Rid[3].hwndTarget = hWnd; - - if (RegisterRawInputDevices(Rid, countof(Rid), sizeof(Rid[0])) == FALSE) - { - //registration failed. Call GetLastError for the cause of the error. - Console.Warning("Could not (de)register raw input devices.\n"); - return 0; - } - return 1; - } - - static ExtraWndProcResult RawInputProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* out) - { - PRAWINPUT pRawInput = nullptr; - UINT bufferSize = 0; - - switch (uMsg) - { - case WM_INPUT: - { - if (skipInput) - break; - - GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER)); - pRawInput = (PRAWINPUT)malloc(bufferSize); - - if (!pRawInput) - break; - - if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER)) > 0) - { - - if (pRawInput->header.dwType == RIM_TYPEKEYBOARD) - ToggleCursor(hWnd, pRawInput->data.keyboard); - - std::lock_guard lk(cb_mutex); - for (auto cb : callbacks) - cb->ParseRawInput(pRawInput); - } - - free(pRawInput); - break; - } - case WM_ENABLE: - skipInput = !wParam; - break; - case WM_ACTIVATE: - skipInput = LOWORD(wParam) == WA_INACTIVE; - if (LOWORD(wParam) == WA_INACTIVE) - CursorRelease(); - break; - case WM_SETFOCUS: - skipInput = false; - break; - case WM_KILLFOCUS: - skipInput = true; - break; - case WM_SIZE: - if (cursorCaptured) - WindowResized(hWnd); - break; - case WM_DESTROY: - Uninitialize(); - break; - } - - return CONTINUE_BLISSFULLY; - } - - int Initialize(void* ptr) - { - skipInput = false; - // Reinitialized without USBclose, like when disc swapping - if (inited) - return 1; - - HWND hWnd = static_cast(ptr); - if (!InitHid()) - return 0; - - RegisterRaw(hWnd); - hWndGSProc.SetWndHandle(hWnd); - hWndGSProc.Eat(RawInputProc, 0); - inited = true; - return 1; - } - - void Uninitialize() - { - if (!inited) - return; - RegisterRaw(nullptr); - hWndGSProc.ReleaseExtraProc(RawInputProc); - inited = false; - } - - } // namespace rawinput -} // namespace shared diff --git a/pcsx2/USB/shared/rawinput_usb.h b/pcsx2/USB/shared/rawinput_usb.h deleted file mode 100644 index 01d0eef660..0000000000 --- a/pcsx2/USB/shared/rawinput_usb.h +++ /dev/null @@ -1,38 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -#include -#include -#include "hidapi.h" - -namespace shared -{ - namespace rawinput - { - - class ParseRawInputCB - { - public: - virtual void ParseRawInput(PRAWINPUT pRawInput) = 0; - }; - - int Initialize(void* hWnd); - void Uninitialize(); - - void RegisterCallback(ParseRawInputCB* cb); - void UnregisterCallback(ParseRawInputCB* cb); - } // namespace rawinput -} // namespace shared diff --git a/pcsx2/USB/shared/ringbuffer.cpp b/pcsx2/USB/shared/ringbuffer.cpp index c3aa67058c..588857b621 100644 --- a/pcsx2/USB/shared/ringbuffer.cpp +++ b/pcsx2/USB/shared/ringbuffer.cpp @@ -170,8 +170,6 @@ void RingBuffer::write(size_t bytes) } else m_end = (m_end + bytes) % m_capacity; - - mLastWrite = hrc::now(); } void RingBuffer::read(size_t bytes) diff --git a/pcsx2/USB/shared/ringbuffer.h b/pcsx2/USB/shared/ringbuffer.h index 0ccb6666da..9928a8d9fc 100644 --- a/pcsx2/USB/shared/ringbuffer.h +++ b/pcsx2/USB/shared/ringbuffer.h @@ -13,17 +13,10 @@ * If not, see . */ -#ifndef RINGBUFFER_H -#define RINGBUFFER_H +#pragma once + #include // for std::min #include -#include - -using hrc = std::chrono::high_resolution_clock; -using ms = std::chrono::milliseconds; -using us = std::chrono::microseconds; -using ns = std::chrono::nanoseconds; -using sec = std::chrono::seconds; class RingBuffer { @@ -98,18 +91,11 @@ public: return (T*)(m_data + m_end); } - long long MilliSecsSinceLastWrite() - { - return std::chrono::duration_cast(hrc::now() - mLastWrite).count(); - } - private: size_t m_begin; size_t m_end; size_t m_capacity; char* m_data; bool m_overrun; - hrc::time_point mLastWrite = hrc::time_point(ns(0)); }; -#endif diff --git a/pcsx2/USB/shared/shared_usb.cpp b/pcsx2/USB/shared/shared_usb.cpp deleted file mode 100644 index dda6e1d032..0000000000 --- a/pcsx2/USB/shared/shared_usb.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "shared_usb.h" -#include - -#ifdef _WIN32 -#include "rawinput_usb.h" -#endif - -namespace shared -{ - - void Initialize(void* ptr) - { -#ifdef _WIN32 - if (!shared::rawinput::Initialize(ptr)) - throw std::runtime_error("Failed to initialize raw input!"); -#endif - } - - void Uninitialize(/*void *ptr*/) - { -#ifdef _WIN32 - shared::rawinput::Uninitialize(/*ptr*/); -#endif - } - -}; // namespace shared diff --git a/pcsx2/USB/shared/shared_usb.h b/pcsx2/USB/shared/shared_usb.h deleted file mode 100644 index 4558e91c2f..0000000000 --- a/pcsx2/USB/shared/shared_usb.h +++ /dev/null @@ -1,21 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -namespace shared -{ - void Initialize(void* ptr); - void Uninitialize(/*void *ptr*/); -}; // namespace shared diff --git a/pcsx2/USB/usb-eyetoy/api_init_linux.cpp b/pcsx2/USB/usb-eyetoy/api_init_linux.cpp deleted file mode 100644 index fbac059bd3..0000000000 --- a/pcsx2/USB/usb-eyetoy/api_init_linux.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "videodeviceproxy.h" -#include "cam-linux.h" - -void usb_eyetoy::RegisterVideoDevice::Register() -{ - auto& inst = RegisterVideoDevice::instance(); - inst.Add(linux_api::APINAME, new VideoDeviceProxy()); -} diff --git a/pcsx2/USB/usb-eyetoy/api_init_win32_eyetoy.cpp b/pcsx2/USB/usb-eyetoy/api_init_win32_eyetoy.cpp deleted file mode 100644 index 6f41feb1d4..0000000000 --- a/pcsx2/USB/usb-eyetoy/api_init_win32_eyetoy.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "videodeviceproxy.h" -#include "cam-windows.h" - -void usb_eyetoy::RegisterVideoDevice::Register() -{ - auto& inst = RegisterVideoDevice::instance(); - inst.Add(windows_api::APINAME, new VideoDeviceProxy()); -} diff --git a/pcsx2/USB/usb-eyetoy/cam-linux.cpp b/pcsx2/USB/usb-eyetoy/cam-linux.cpp index a61282975c..df60a48104 100644 --- a/pcsx2/USB/usb-eyetoy/cam-linux.cpp +++ b/pcsx2/USB/usb-eyetoy/cam-linux.cpp @@ -18,7 +18,6 @@ #include "jpgd.h" #include "jpge.h" #include "jo_mpeg.h" -#include "USB/gtk.h" #include "common/Console.h" #include @@ -242,9 +241,9 @@ namespace usb_eyetoy return 1; } - std::vector getDevList() + std::vector> getDevList() { - std::vector devList; + std::vector> devList; char dev_name[64]; int fd; struct v4l2_capability cap; @@ -260,7 +259,7 @@ namespace usb_eyetoy if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) { - devList.push_back((char*)cap.card); + devList.emplace_back((char*)cap.card, (char*)cap.card); } close(fd); @@ -603,9 +602,8 @@ namespace usb_eyetoy free(comprBuf); } - V4L2::V4L2(int port) + V4L2::V4L2() { - mPort = port; mpeg_buffer.start = calloc(1, 640 * 480 * 2); } @@ -636,9 +634,7 @@ namespace usb_eyetoy pthread_join(eyetoy_thread, NULL); v4l_close(); } - std::string selectedDevice; - LoadSetting(EyeToyWebCamDevice::TypeName(), mPort, APINAME, N_DEVICE, selectedDevice); - if (v4l_open(selectedDevice) != 0) + if (v4l_open(mHostDevice.c_str()) != 0) return -1; pthread_create(&eyetoy_thread, NULL, &v4l_thread, NULL); eyetoy_running = 1; @@ -674,76 +670,15 @@ namespace usb_eyetoy { mirroring_enabled = state; } - - static void deviceChanged(GtkComboBox* widget, gpointer data) - { - *(int*)data = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - } - - int GtkConfigure(int port, const char* dev_type, void* data) - { - std::string selectedDevice; - LoadSetting(dev_type, port, APINAME, N_DEVICE, selectedDevice); - - GtkWidget* dlg = gtk_dialog_new_with_buttons( - "V4L2 Settings", GTK_WINDOW(data), GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE); - gtk_window_set_default_size(GTK_WINDOW(dlg), 320, 75); - - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - GtkWidget* main_hbox = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(dlg_area_box), main_hbox); - GtkWidget* right_vbox = gtk_vbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(main_hbox), right_vbox, TRUE, TRUE, 5); - - GtkWidget* rs_cb = new_combobox("Device:", right_vbox); - - std::vector devList = getDevList(); - int sel_idx = 0; - for (uint32_t idx = 0; idx < (uint32_t)devList.size(); idx++) - { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), devList.at(idx).c_str()); - if (!selectedDevice.empty() && selectedDevice == devList.at(idx)) - { - gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), idx); - sel_idx = idx; - } - } - - int sel_new = 0; - g_signal_connect(G_OBJECT(rs_cb), "changed", G_CALLBACK(deviceChanged), (gpointer)&sel_new); - - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - - int ret = RESULT_OK; - if (result == GTK_RESPONSE_OK) - { - if (devList.size() && sel_new != sel_idx) - { - if (!SaveSetting(dev_type, port, APINAME, N_DEVICE, devList.at(sel_new))) - { - ret = RESULT_FAILED; - } - } - } - else - { - ret = RESULT_CANCELED; - } - - gtk_widget_destroy(dlg); - return ret; - } - - int V4L2::Configure(int port, const char* dev_type, void* data) - { - return GtkConfigure(port, dev_type, data); - }; - } // namespace linux_api + + std::unique_ptr VideoDevice::CreateInstance() + { + return std::make_unique(); + } + + std::vector> VideoDevice::GetDeviceList() + { + return linux_api::getDevList(); + } } // namespace usb_eyetoy diff --git a/pcsx2/USB/usb-eyetoy/cam-linux.h b/pcsx2/USB/usb-eyetoy/cam-linux.h index e44c595d7b..c05de06242 100644 --- a/pcsx2/USB/usb-eyetoy/cam-linux.h +++ b/pcsx2/USB/usb-eyetoy/cam-linux.h @@ -19,6 +19,7 @@ namespace usb_eyetoy { namespace linux_api { + std::vector> getDevList(); typedef struct _buffer_t { @@ -26,31 +27,16 @@ namespace usb_eyetoy size_t length; } buffer_t; - static const char* APINAME = "V4L2"; - class V4L2 : public VideoDevice { public: - V4L2(int port); + V4L2(); ~V4L2(); int Open(int width, int height, FrameFormat format, int mirror); int Close(); int GetImage(uint8_t* buf, size_t len); void SetMirroring(bool state); int Reset() { return 0; }; - - static const TCHAR* Name() - { - return TEXT("V4L2"); - } - static int Configure(int port, const char* dev_type, void* data); - - int Port() { return mPort; } - void Port(int port) { mPort = port; } - - private: - int mPort; }; - } // namespace linux_api } // namespace usb_eyetoy diff --git a/pcsx2/USB/usb-eyetoy/cam-noop.cpp b/pcsx2/USB/usb-eyetoy/cam-noop.cpp new file mode 100644 index 0000000000..607c2ec8bc --- /dev/null +++ b/pcsx2/USB/usb-eyetoy/cam-noop.cpp @@ -0,0 +1,67 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2020 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" + +#include "common/StringUtil.h" + +#include "videodev.h" +#include "usb-eyetoy-webcam.h" +#include "jo_mpeg.h" +#include "USB/USB.h" + +namespace usb_eyetoy +{ + namespace noop_api + { + class NoopVideoDevice final : public VideoDevice + { + public: + int Open(int width, int height, FrameFormat format, int mirror) override + { + return -1; + } + + int Close() override + { + return 0; + } + + int GetImage(uint8_t* buf, size_t len) override + { + return 0; + } + + void SetMirroring(bool state) override + { + } + + int Reset() override + { + return 0; + } + }; + } // namespace noop_api + + std::unique_ptr VideoDevice::CreateInstance() + { + return std::make_unique(); + } + + std::vector> VideoDevice::GetDeviceList() + { + return {}; + } +} // namespace usb_eyetoy diff --git a/pcsx2/USB/usb-eyetoy/cam-windows.cpp b/pcsx2/USB/usb-eyetoy/cam-windows.cpp index 09236ee181..c52d5316f6 100644 --- a/pcsx2/USB/usb-eyetoy/cam-windows.cpp +++ b/pcsx2/USB/usb-eyetoy/cam-windows.cpp @@ -15,14 +15,14 @@ #include "PrecompiledHeader.h" +#include "common/StringUtil.h" + #include #include "videodev.h" #include "cam-windows.h" #include "usb-eyetoy-webcam.h" #include "jo_mpeg.h" - -#include "USB/Win32/Config_usb.h" -#include "USB/Win32/resource_usb.h" +#include "USB/USB.h" namespace usb_eyetoy { @@ -59,9 +59,9 @@ namespace usb_eyetoy return E_NOINTERFACE; } - std::vector getDevList() + std::vector> getDevList() { - std::vector devList; + std::vector> devList; ICreateDevEnum* pCreateDevEnum = nullptr; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pCreateDevEnum)); @@ -100,7 +100,8 @@ namespace usb_eyetoy } if (SUCCEEDED(hr)) { - devList.push_back(var.bstrVal); + std::string u8name(StringUtil::WideStringToUTF8String(var.bstrVal)); + devList.emplace_back(u8name, u8name); VariantClear(&var); } @@ -203,7 +204,8 @@ namespace usb_eyetoy goto freeVar; } - hr = pGraphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter, IID_IAMStreamConfig, (void**)&pSourceConfig); + hr = pGraphBuilder->FindInterface( + &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter, IID_IAMStreamConfig, (void**)&pSourceConfig); if (SUCCEEDED(hr)) { int iCount = 0, iSize = 0; @@ -218,17 +220,13 @@ namespace usb_eyetoy VIDEO_STREAM_CONFIG_CAPS scc; AM_MEDIA_TYPE* pmtConfig; hr = pSourceConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc); - Console.Warning("Camera: GetStreamCaps min=%dx%d max=%dx%d, fmt=%x", - scc.MinOutputSize.cx, scc.MinOutputSize.cy, - scc.MaxOutputSize.cx, scc.MaxOutputSize.cy, - pmtConfig->subtype); + Console.Warning("Camera: GetStreamCaps min=%dx%d max=%dx%d, fmt=%x", scc.MinOutputSize.cx, scc.MinOutputSize.cy, + scc.MaxOutputSize.cx, scc.MaxOutputSize.cy, pmtConfig->subtype); if (SUCCEEDED(hr)) { - if ((pmtConfig->majortype == MEDIATYPE_Video) && - (pmtConfig->formattype == FORMAT_VideoInfo) && - (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && - (pmtConfig->pbFormat != nullptr)) + if ((pmtConfig->majortype == MEDIATYPE_Video) && (pmtConfig->formattype == FORMAT_VideoInfo) && + (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && (pmtConfig->pbFormat != nullptr)) { VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat; pVih->bmiHeader.biWidth = frame_width; @@ -383,7 +381,8 @@ namespace usb_eyetoy int comprLen = 0; if (frame_format == format_mpeg) { - comprLen = jo_write_mpeg(comprBuf, data, frame_width, frame_height, JO_BGR24, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_FLIP_Y); + comprLen = jo_write_mpeg( + comprBuf, data, frame_width, frame_height, JO_BGR24, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_FLIP_Y); } else if (frame_format == format_jpeg) { @@ -419,8 +418,8 @@ namespace usb_eyetoy for (int y = 0; y < 8; y++) for (int x = 0; x < 8; x++) { - int srcx = 4* (8*mx + x); - int srcy = frame_height - 4* (8*my + y) - 1; + int srcx = 4 * (8 * mx + x); + int srcy = frame_height - 4 * (8 * my + y) - 1; unsigned char* src = data + (srcy * frame_width + srcx) * bytesPerPixel; if (srcy < 0) { @@ -501,9 +500,8 @@ namespace usb_eyetoy free(comprBuf); } - DirectShow::DirectShow(int port) + DirectShow::DirectShow() { - mPort = port; pGraphBuilder = nullptr; pGraph = nullptr; pControl = nullptr; @@ -539,13 +537,10 @@ namespace usb_eyetoy create_dummy_frame_eyetoy(); } - std::wstring selectedDevice; - LoadSetting(EyeToyWebCamDevice::TypeName(), Port(), APINAME, N_DEVICE, selectedDevice); - - int ret = InitializeDevice(selectedDevice); + int ret = InitializeDevice(StringUtil::UTF8StringToWideString(mHostDevice)); if (ret < 0) { - Console.Warning("Camera: cannot find '%ls'", selectedDevice.c_str()); + Console.Warning("Camera: cannot find '%s'", mHostDevice.c_str()); return -1; } @@ -590,75 +585,16 @@ namespace usb_eyetoy return len2; }; - void DirectShow::SetMirroring(bool state) - { - mirroring_enabled = state; - } - - BOOL CALLBACK DirectShowDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - int port; - - switch (uMsg) - { - case WM_CREATE: - SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam); - break; - case WM_INITDIALOG: - { - port = (int)lParam; - SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam); - - std::wstring selectedDevice; - LoadSetting(EyeToyWebCamDevice::TypeName(), port, APINAME, N_DEVICE, selectedDevice); - SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_RESETCONTENT, 0, 0); - - std::vector devList = getDevList(); - for (auto i = 0; i != devList.size(); i++) - { - SendDlgItemMessageW(hW, IDC_COMBO1_USB, CB_ADDSTRING, 0, (LPARAM)devList[i].c_str()); - if (selectedDevice == devList.at(i)) - { - SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_SETCURSEL, i, i); - } - } - return TRUE; - } - case WM_COMMAND: - if (HIWORD(wParam) == BN_CLICKED) - { - switch (LOWORD(wParam)) - { - case IDOK: - { - INT_PTR res = RESULT_OK; - static wchar_t selectedDevice[500] = {0}; - GetWindowTextW(GetDlgItem(hW, IDC_COMBO1_USB), selectedDevice, countof(selectedDevice)); - port = (int)GetWindowLongPtr(hW, GWLP_USERDATA); - if (!SaveSetting(EyeToyWebCamDevice::TypeName(), port, APINAME, N_DEVICE, selectedDevice)) - { - res = RESULT_FAILED; - } - EndDialog(hW, res); - return TRUE; - } - case IDCANCEL: - EndDialog(hW, RESULT_CANCELED); - return TRUE; - } - } - } - return FALSE; - } - - int DirectShow::Configure(int port, const char* dev_type, void* data) - { - Win32Handles handles = *(Win32Handles*)data; - return DialogBoxParam(handles.hInst, - MAKEINTRESOURCE(IDD_DLG_EYETOY_USB), - handles.hWnd, - (DLGPROC)DirectShowDlgProc, port); - }; - + void DirectShow::SetMirroring(bool state) { mirroring_enabled = state; } } // namespace windows_api + + std::unique_ptr VideoDevice::CreateInstance() + { + return std::make_unique(); + } + + std::vector> VideoDevice::GetDeviceList() + { + return windows_api::getDevList(); + } } // namespace usb_eyetoy diff --git a/pcsx2/USB/usb-eyetoy/cam-windows.h b/pcsx2/USB/usb-eyetoy/cam-windows.h index 3e9c5104e2..2ac49c4725 100644 --- a/pcsx2/USB/usb-eyetoy/cam-windows.h +++ b/pcsx2/USB/usb-eyetoy/cam-windows.h @@ -30,15 +30,13 @@ extern GUID CLSID_NullRenderer; } #pragma region qedit.h -struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85")) - ISampleGrabberCB : IUnknown +struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85")) ISampleGrabberCB : IUnknown { virtual HRESULT __stdcall SampleCB(double SampleTime, struct IMediaSample* pSample) = 0; virtual HRESULT __stdcall BufferCB(double SampleTime, unsigned char* pBuffer, long BufferLen) = 0; }; -struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f")) - ISampleGrabber : IUnknown +struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f")) ISampleGrabber : IUnknown { virtual HRESULT __stdcall SetOneShot(long OneShot) = 0; virtual HRESULT __stdcall SetMediaType(struct _AMMediaType* pType) = 0; @@ -49,8 +47,7 @@ struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f")) virtual HRESULT __stdcall SetCallback(struct ISampleGrabberCB* pCallback, long WhichMethodToCallback) = 0; }; -struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37")) - SampleGrabber; +struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37")) SampleGrabber; #pragma endregion @@ -71,6 +68,7 @@ namespace usb_eyetoy { namespace windows_api { + std::vector> getDevList(); typedef void (*DShowVideoCaptureCallback)(unsigned char* data, int len, int bitsperpixel); @@ -80,12 +78,10 @@ namespace usb_eyetoy size_t length = 0; }; - static const char* APINAME = "DirectShow"; - class DirectShow : public VideoDevice { public: - DirectShow(int port); + DirectShow(); ~DirectShow(); int Open(int width, int height, FrameFormat format, int mirror); int Close(); @@ -93,15 +89,6 @@ namespace usb_eyetoy void SetMirroring(bool state); int Reset() { return 0; }; - static const TCHAR* Name() - { - return TEXT("DirectShow"); - } - static int Configure(int port, const char* dev_type, void* data); - - int Port() { return mPort; } - void Port(int port) { mPort = port; } - protected: void SetCallback(DShowVideoCaptureCallback cb) { callbackhandler->SetCallback(cb); } void Start(); @@ -109,8 +96,6 @@ namespace usb_eyetoy int InitializeDevice(std::wstring selectedDevice); private: - int mPort; - wil::unique_couninitialize_call dshowCoInitialize; ICaptureGraphBuilder2* pGraphBuilder; IFilterGraph2* pGraph; diff --git a/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp b/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp index b14d0c73df..62673759a0 100644 --- a/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp +++ b/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp @@ -30,7 +30,6 @@ #include "PrecompiledHeader.h" #include #include -#include #include "jo_mpeg.h" diff --git a/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp b/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp index 8d943c0591..2eb719edd4 100644 --- a/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp +++ b/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp @@ -14,11 +14,12 @@ */ #include "PrecompiledHeader.h" -#include "videodeviceproxy.h" +#include "videodev.h" #include "usb-eyetoy-webcam.h" #include "ov519.h" #include "USB/qemu-usb/desc.h" -#include "USB/shared/inifile_usb.h" +#include "USB/USB.h" +#include "StateWrapper.h" namespace usb_eyetoy { @@ -28,21 +29,22 @@ namespace usb_eyetoy USBDesc desc; USBDescDevice desc_dev; - VideoDevice* videodev; + u32 port; + u32 subtype; + + std::unique_ptr videodev; // struct freeze { - uint8_t regs[0xFF]; //OV519 + uint8_t regs[0xFF]; //OV519 uint8_t i2c_regs[0xFF]; //OV764x int hw_camera_running; int frame_step; - unsigned char* mpeg_frame_data; + std::unique_ptr mpeg_frame_data; unsigned int mpeg_frame_size; unsigned int mpeg_frame_offset; // } f; } EYETOYState; - static EYETOYState* static_state; - static const USBDescStrings desc_strings = { "", "Sony corporation", @@ -51,11 +53,11 @@ namespace usb_eyetoy static void reset_controller(EYETOYState* s) { - if (s->videodev->Type() == TYPE_EYETOY) + if (s->subtype == TYPE_EYETOY) { memcpy(s->regs, ov519_defaults, sizeof(s->regs)); } - else if (s->videodev->Type() == TYPE_OV511P) + else if (s->subtype == TYPE_OV511P) { memcpy(s->regs, ov511p_defaults, sizeof(s->regs)); } @@ -63,26 +65,61 @@ namespace usb_eyetoy static void reset_sensor(EYETOYState* s) { - if (s->videodev->Type() == TYPE_EYETOY) + if (s->subtype == TYPE_EYETOY) { memcpy(s->i2c_regs, ov7648_defaults, sizeof(s->regs)); } - else if (s->videodev->Type() == TYPE_OV511P) + else if (s->subtype == TYPE_OV511P) { memcpy(s->i2c_regs, ov7620_defaults, sizeof(s->regs)); } } - static void eyetoy_handle_reset(USBDevice* dev) + static void open_camera(EYETOYState* s) { - reset_controller((EYETOYState*)dev); - reset_sensor((EYETOYState*)dev); + if (s->hw_camera_running && s->subtype == TYPE_EYETOY) + { + const int width = s->regs[OV519_R10_H_SIZE] << 4; + const int height = s->regs[OV519_R11_V_SIZE] << 3; + const FrameFormat format = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? format_jpeg : format_mpeg; + const int mirror = !!(s->i2c_regs[OV7610_REG_COM_A] & OV7610_REG_COM_A_MASK_MIRROR); + Console.WriteLn( + "EyeToy : eyetoy_open(); hw=%d, w=%d, h=%d, fmt=%d, mirr=%d", s->hw_camera_running, width, height, format, mirror); + if (s->videodev->Open(width, height, format, mirror) != 0) + Console.Error("(Eyetoy) Failed to open video device"); + } + else if (s->hw_camera_running && s->subtype == TYPE_OV511P) + { + const int width = 320; + const int height = 240; + const FrameFormat format = format_yuv400; + const int mirror = 0; + Console.WriteLn( + "EyeToy : eyetoy_open(); hw=%d, w=%d, h=%d, fmt=%d, mirr=%d", s->hw_camera_running, width, height, format, mirror); + if (s->videodev->Open(width, height, format, mirror) != 0) + Console.Error("(Eyetoy) Failed to open video device"); + } } - static void webcam_handle_control_eyetoy(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + static void close_camera(EYETOYState* s) { - EYETOYState* s = (EYETOYState*)dev; + Console.WriteLn("EyeToy : eyetoy_close(); hw=%d", s->hw_camera_running); + if (s->hw_camera_running) + { + s->hw_camera_running = 0; + s->videodev->Close(); + } + } + + static void eyetoy_handle_reset(USBDevice* dev) + { + reset_controller(USB_CONTAINER_OF(dev, EYETOYState, dev)); + reset_sensor(USB_CONTAINER_OF(dev, EYETOYState, dev)); + } + + static void webcam_handle_control_eyetoy(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) + { + EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev); int ret = 0; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); @@ -118,8 +155,8 @@ namespace usb_eyetoy if (s->hw_camera_running && s->regs[OV519_RA0_FORMAT] != data[0]) { Console.WriteLn("EyeToy : reinitialize the camera"); - s->dev.klass.close(dev); - s->dev.klass.open(dev); + close_camera(s); + open_camera(s); } break; case OV519_R10_H_SIZE: @@ -129,15 +166,15 @@ namespace usb_eyetoy Console.WriteLn("EyeToy : Image height : %d", data[0] << 3); break; case OV519_GPIO_DATA_OUT0: + { + static char led_state = -1; + if (led_state != data[0]) { - static char led_state = -1; - if (led_state != data[0]) - { - led_state = data[0]; - Console.WriteLn("EyeToy : LED : %d", !!led_state); - } + led_state = data[0]; + Console.WriteLn("EyeToy : LED : %d", !!led_state); } - break; + } + break; case R518_I2C_CTL: if (data[0] == 1) // Commit I2C write { @@ -187,10 +224,9 @@ namespace usb_eyetoy } } - static void webcam_handle_control_ov511p(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + static void webcam_handle_control_ov511p(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) { - EYETOYState* s = (EYETOYState*)dev; + EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev); int ret = 0; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); @@ -246,7 +282,7 @@ namespace usb_eyetoy static void webcam_handle_data_eyetoy(USBDevice* dev, USBPacket* p) { - EYETOYState* s = (EYETOYState*)dev; + EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev); static const int max_ep_size = 896; uint8_t devep = p->ep->nr; @@ -254,7 +290,7 @@ namespace usb_eyetoy { Console.WriteLn("EyeToy : initialization done; start the camera"); s->hw_camera_running = 1; - s->dev.klass.open(dev); + open_camera(s); } switch (p->pid) @@ -267,20 +303,19 @@ namespace usb_eyetoy if (s->frame_step == 0) { - s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data, 640 * 480 * 3); + s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data.get(), 640 * 480 * 3); if (s->mpeg_frame_size == 0) { p->status = USB_RET_NAK; break; } - uint8_t header[] = { - 0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t header[] = {0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; header[0x0A] = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? 0x03 : 0x01; memcpy(data, header, sizeof(header)); int data_pk = max_ep_size - sizeof(header); - memcpy(data + sizeof(header), s->mpeg_frame_data, data_pk); + memcpy(data + sizeof(header), s->mpeg_frame_data.get(), data_pk); s->mpeg_frame_offset = data_pk; s->frame_step++; } @@ -289,14 +324,13 @@ namespace usb_eyetoy int data_pk = s->mpeg_frame_size - s->mpeg_frame_offset; if (data_pk > max_ep_size) data_pk = max_ep_size; - memcpy(data, s->mpeg_frame_data + s->mpeg_frame_offset, data_pk); + memcpy(data, s->mpeg_frame_data.get() + s->mpeg_frame_offset, data_pk); s->mpeg_frame_offset += data_pk; s->frame_step++; } else { - uint8_t footer[] = { - 0xFF, 0xFF, 0xFF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t footer[] = {0xFF, 0xFF, 0xFF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; footer[0x0A] = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? 0x03 : 0x01; memcpy(data, footer, sizeof(footer)); s->frame_step = 0; @@ -321,7 +355,7 @@ namespace usb_eyetoy static void webcam_handle_data_ov511p(USBDevice* dev, USBPacket* p) { - EYETOYState* s = (EYETOYState*)dev; + EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev); static const int max_ep_size = 960; // 961 uint8_t devep = p->ep->nr; @@ -329,7 +363,7 @@ namespace usb_eyetoy { Console.WriteLn("EyeToy : initialization done; start the camera"); s->hw_camera_running = 1; - s->dev.klass.open(dev); + open_camera(s); } switch (p->pid) @@ -342,7 +376,7 @@ namespace usb_eyetoy if (s->frame_step == 0) { - s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data, 640 * 480 * 3); + s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data.get(), 640 * 480 * 3); if (s->mpeg_frame_size == 0) { p->status = USB_RET_NAK; @@ -353,7 +387,7 @@ namespace usb_eyetoy memcpy(data, header, sizeof(header)); int data_pk = max_ep_size - sizeof(header); - memcpy(data + sizeof(header), s->mpeg_frame_data, data_pk); + memcpy(data + sizeof(header), s->mpeg_frame_data.get(), data_pk); s->mpeg_frame_offset = data_pk; s->frame_step++; } @@ -362,7 +396,7 @@ namespace usb_eyetoy int data_pk = s->mpeg_frame_size - s->mpeg_frame_offset; if (data_pk > max_ep_size) data_pk = max_ep_size; - memcpy(data, s->mpeg_frame_data + s->mpeg_frame_offset, data_pk); + memcpy(data, s->mpeg_frame_data.get() + s->mpeg_frame_offset, data_pk); s->mpeg_frame_offset += data_pk; s->frame_step++; } @@ -385,80 +419,28 @@ namespace usb_eyetoy static void eyetoy_handle_destroy(USBDevice* dev) { - EYETOYState* s = (EYETOYState*)dev; + EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev); + close_camera(s); delete s; } - int eyetoy_open(USBDevice* dev) + USBDevice* EyeToyWebCamDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { - EYETOYState* s = (EYETOYState*)dev; - if (s->hw_camera_running && s->videodev->Type() == TYPE_EYETOY) - { - const int width = s->regs[OV519_R10_H_SIZE] << 4; - const int height = s->regs[OV519_R11_V_SIZE] << 3; - const FrameFormat format = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? format_jpeg : format_mpeg; - const int mirror = !!(s->i2c_regs[OV7610_REG_COM_A] & OV7610_REG_COM_A_MASK_MIRROR); - Console.Error("EyeToy : eyetoy_open(); hw=%d, w=%d, h=%d, fmt=%d, mirr=%d", s->hw_camera_running, - width, height, format, mirror); - s->videodev->Open(width, height, format, mirror); - } - else if (s->hw_camera_running && s->videodev->Type() == TYPE_OV511P) - { - const int width = 320; - const int height = 240; - const FrameFormat format = format_yuv400; - const int mirror = 0; - Console.Error("EyeToy : eyetoy_open(); hw=%d, w=%d, h=%d, fmt=%d, mirr=%d", s->hw_camera_running, - width, height, format, mirror); - s->videodev->Open(width, height, format, mirror); - } - return 1; - } - - void eyetoy_close(USBDevice* dev) - { - EYETOYState* s = (EYETOYState*)dev; - Console.Error("EyeToy : eyetoy_close(); hw=%d", s->hw_camera_running); - if (s->hw_camera_running) - { - s->hw_camera_running = 0; - s->videodev->Close(); - } - } - - USBDevice* EyeToyWebCamDevice::CreateDevice(int port) - { - VideoDevice* videodev = nullptr; - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - VideoDeviceProxyBase* proxy = RegisterVideoDevice::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("Invalid video device API: %" SFMTs "\n", varApi.c_str()); - return NULL; - } - - videodev = proxy->CreateObject(port); + std::unique_ptr videodev(VideoDevice::CreateInstance()); if (!videodev) - return NULL; + { + Console.Error("Failed to create video device."); + return nullptr; + } - videodev->Type(GetSelectedSubtype(std::make_pair(port, TypeName()))); - - EYETOYState* s; - s = new EYETOYState(); - if (!s) - return NULL; + videodev->HostDevice(USB::GetConfigString(si, port, TypeName(), "device_name")); + EYETOYState* s = new EYETOYState(); + s->subtype = subtype; s->desc.full = &s->desc_dev; s->desc.str = desc_strings; - if (videodev->Type() == TYPE_EYETOY) + if (subtype == TYPE_EYETOY) { if (usb_desc_parse_dev(eyetoy_dev_descriptor, sizeof(eyetoy_dev_descriptor), s->desc, s->desc_dev) < 0) goto fail; @@ -467,7 +449,7 @@ namespace usb_eyetoy s->dev.klass.handle_control = webcam_handle_control_eyetoy; s->dev.klass.handle_data = webcam_handle_data_eyetoy; } - else if (videodev->Type() == TYPE_OV511P) + else if (subtype == TYPE_OV511P) { if (usb_desc_parse_dev(ov511p_dev_descriptor, sizeof(ov511p_dev_descriptor), s->desc, s->desc_dev) < 0) goto fail; @@ -477,59 +459,71 @@ namespace usb_eyetoy s->dev.klass.handle_data = webcam_handle_data_ov511p; } - s->videodev = videodev; + s->videodev = std::move(videodev); s->dev.speed = USB_SPEED_FULL; s->dev.klass.handle_attach = usb_desc_attach; s->dev.klass.handle_reset = eyetoy_handle_reset; s->dev.klass.unrealize = eyetoy_handle_destroy; - s->dev.klass.open = eyetoy_open; - s->dev.klass.close = eyetoy_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = s->desc.str[2]; usb_desc_init(&s->dev); usb_ep_init(&s->dev); - eyetoy_handle_reset((USBDevice*)s); + eyetoy_handle_reset(&s->dev); s->hw_camera_running = 0; s->frame_step = 0; - s->mpeg_frame_data = (unsigned char*)calloc(1, 640 * 480 * 3); + s->mpeg_frame_data = std::make_unique(640 * 480 * 3); + std::memset(s->mpeg_frame_data.get(), 0, 640 * 480 * 3); s->mpeg_frame_offset = 0; - static_state = s; - return (USBDevice*)s; + return &s->dev; fail: - eyetoy_handle_destroy((USBDevice*)s); + eyetoy_handle_destroy(&s->dev); return nullptr; } - int EyeToyWebCamDevice::Configure(int port, const std::string& api, void* data) + const char* EyeToyWebCamDevice::Name() const { - auto proxy = RegisterVideoDevice::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; + return "Webcam (EyeToy)"; } - int EyeToyWebCamDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* EyeToyWebCamDevice::TypeName() const { - /*switch (mode) - { - case FREEZE_LOAD: - if (!s) return -1; - s->f = *(PADState::freeze *)data; - s->pad->Type((PS2WheelTypes)s->f.wheel_type); - return sizeof(PADState::freeze); - case FREEZE_SAVE: - if (!s) return -1; - *(PADState::freeze *)data = s->f; - return sizeof(PADState::freeze); - case FREEZE_SIZE: - return sizeof(PADState::freeze); - default: - break; - }*/ - return 0; + return "webcam"; } + bool EyeToyWebCamDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev); + if (!sw.DoMarker("EYETOYState")) + return false; + + sw.DoBytes(s->regs, sizeof(s->regs)); + sw.DoBytes(s->i2c_regs, sizeof(s->i2c_regs)); + sw.Do(&s->frame_step); + sw.DoBytes(s->mpeg_frame_data.get(), 640 * 480 * 3); + sw.Do(&s->mpeg_frame_size); + sw.Do(&s->mpeg_frame_offset); + return !sw.HasError(); + } + + void EyeToyWebCamDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const + { + // TODO: Update device name + } + + std::vector EyeToyWebCamDevice::SubTypes() const + { + return {"Sony EyeToy", "Konami Capture Eye"}; + } + + gsl::span EyeToyWebCamDevice::Settings(u32 subtype) const + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::StringList, "device_name", "Device Name", "Selects the device to capture images from.", "", nullptr, + nullptr, nullptr, nullptr, nullptr, &VideoDevice::GetDeviceList}, + }; + return info; + } } // namespace usb_eyetoy diff --git a/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.h b/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.h index af67ddb2c5..51001372e0 100644 --- a/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.h +++ b/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.h @@ -13,13 +13,11 @@ * If not, see . */ -#ifndef USBEYETOYWEBCAM_H -#define USBEYETOYWEBCAM_H +#pragma once -#include "USB/qemu-usb/vl.h" -#include "USB/configuration.h" +#include "USB/qemu-usb/qusb.h" #include "USB/deviceproxy.h" -#include "videodeviceproxy.h" +#include "USB/usb-eyetoy/videodev.h" #include @@ -469,37 +467,16 @@ namespace usb_eyetoy 0x75, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - class EyeToyWebCamDevice + class EyeToyWebCamDevice final : public DeviceProxy { public: - virtual ~EyeToyWebCamDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Webcam (EyeToy)"); - } - static const char* TypeName() - { - return "webcam"; - } - static std::list ListAPIs() - { - return RegisterVideoDevice::instance().Names(); - } - static const TCHAR* LongAPIName(const std::string& name) - { - auto proxy = RegisterVideoDevice::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {"Sony EyeToy", "Konami Capture Eye"}; - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* Name() const override; + const char* TypeName() const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override; + std::vector SubTypes() const override; + gsl::span Settings(u32 subtype) const override; }; } // namespace usb_eyetoy -#endif diff --git a/pcsx2/USB/usb-eyetoy/videodev.h b/pcsx2/USB/usb-eyetoy/videodev.h index 694e92f21f..d1723508fb 100644 --- a/pcsx2/USB/usb-eyetoy/videodev.h +++ b/pcsx2/USB/usb-eyetoy/videodev.h @@ -13,10 +13,11 @@ * If not, see . */ -#ifndef VIDEODEV_H -#define VIDEODEV_H -#include "USB/qemu-usb/vl.h" -#include "USB/configuration.h" +#pragma once +#include "USB/qemu-usb/qusb.h" +#include +#include +#include namespace usb_eyetoy { @@ -43,15 +44,13 @@ namespace usb_eyetoy virtual void SetMirroring(bool state) = 0; virtual int Reset() = 0; - virtual int Port() { return mPort; } - virtual void Port(int port) { mPort = port; } - virtual int Type() { return mType; } - virtual void Type(int type) { mType = type; } + virtual const std::string& HostDevice() const { return mHostDevice; } + virtual void HostDevice(std::string dev) { mHostDevice = std::move(dev); } + + static std::unique_ptr CreateInstance(); + static std::vector> GetDeviceList(); protected: - int mPort; - int mType; + std::string mHostDevice; }; - } // namespace usb_eyetoy -#endif diff --git a/pcsx2/USB/usb-eyetoy/videodeviceproxy.h b/pcsx2/USB/usb-eyetoy/videodeviceproxy.h deleted file mode 100644 index 379b2e6828..0000000000 --- a/pcsx2/USB/usb-eyetoy/videodeviceproxy.h +++ /dev/null @@ -1,90 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef VIDEODEVICEPROXY_H -#define VIDEODEVICEPROXY_H -#include -#include -#include -#include -#include -#include "videodev.h" -#include "USB/helpers.h" -#include "USB/deviceproxy.h" - -namespace usb_eyetoy -{ - - class VideoDeviceError : public std::runtime_error - { - public: - VideoDeviceError(const char* msg) - : std::runtime_error(msg) - { - } - virtual ~VideoDeviceError() throw() {} - }; - - class VideoDeviceProxyBase : public ProxyBase - { - VideoDeviceProxyBase(const VideoDeviceProxyBase&) = delete; - - public: - VideoDeviceProxyBase() {} - VideoDeviceProxyBase(const std::string& name); - virtual VideoDevice* CreateObject(int port) const = 0; - }; - - template - class VideoDeviceProxy : public VideoDeviceProxyBase - { - VideoDeviceProxy(const VideoDeviceProxy&) = delete; - - public: - VideoDeviceProxy() {} - VideoDeviceProxy(const std::string& name) - : VideoDeviceProxyBase(name) - { - } - VideoDevice* CreateObject(int port) const - { - try - { - return new T(port); - } - catch (VideoDeviceError& err) - { - (void)err; - return nullptr; - } - } - virtual const TCHAR* Name() const - { - return T::Name(); - } - virtual int Configure(int port, const char* dev_type, void* data) - { - return T::Configure(port, dev_type, data); - } - }; - - class RegisterVideoDevice : public RegisterProxy - { - public: - static void Register(); - }; - -} // namespace usb_eyetoy -#endif diff --git a/pcsx2/USB/usb-hid/api_init_linux.cpp b/pcsx2/USB/usb-hid/api_init_linux.cpp deleted file mode 100644 index 36fbaaab0c..0000000000 --- a/pcsx2/USB/usb-hid/api_init_linux.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "hidproxy.h" -#include "evdev/evdev.h" -#include "noop.h" - -void usb_hid::RegisterUsbHID::Register() -{ - auto& inst = RegisterUsbHID::instance(); - inst.Add(usb_hid::evdev::APINAME, new UsbHIDProxy()); - inst.Add(usb_hid::noop::APINAME, new UsbHIDProxy()); -} diff --git a/pcsx2/USB/usb-hid/api_init_win32_hid.cpp b/pcsx2/USB/usb-hid/api_init_win32_hid.cpp deleted file mode 100644 index 3894519d8f..0000000000 --- a/pcsx2/USB/usb-hid/api_init_win32_hid.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "hidproxy.h" -#include "raw/rawinput.h" -#include "noop.h" - -void usb_hid::RegisterUsbHID::Register() -{ - auto& inst = RegisterUsbHID::instance(); - inst.Add(usb_hid::raw::APINAME, new UsbHIDProxy()); - inst.Add(usb_hid::noop::APINAME, new UsbHIDProxy()); -} diff --git a/pcsx2/USB/usb-hid/evdev/evdev-gtk.cpp b/pcsx2/USB/usb-hid/evdev/evdev-gtk.cpp deleted file mode 100644 index 6aa906676f..0000000000 --- a/pcsx2/USB/usb-hid/evdev/evdev-gtk.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "USB/usb-hid/usb-hid.h" -#include "evdev.h" -#include -#include "USB/gtk.h" -#include -#include - -namespace usb_hid -{ - namespace evdev - { - -#define EVDEV_DIR "/dev/input/by-path/" - - typedef std::vector> devs_t; - struct ConfigData - { - int port; - devs_t devs; - devs_t::const_iterator iter; - }; - - static void PopulateHIDs(ConfigData& cfg, HIDType hid_type) - { - std::stringstream str; - struct dirent* dp; - const char* devstr[] = {"event-kbd", "event-mouse"}; - - cfg.devs.clear(); - cfg.devs.push_back(std::make_pair("None", "")); - - DIR* dirp = opendir(EVDEV_DIR); - if (dirp == NULL) - { - Console.Warning("Error opening " EVDEV_DIR ": %s\n", strerror(errno)); - return; - } - - // Loop over dir entries using readdir - int len = strlen(devstr[hid_type]); - while ((dp = readdir(dirp)) != NULL) - { - // Only select names that end in 'event-joystick' - int devlen = strlen(dp->d_name); - if (devlen >= len) - { - const char* const start = dp->d_name + devlen - len; - if (strncmp(start, devstr[hid_type], len) == 0) - { - - str.clear(); - str.str(""); - str << EVDEV_DIR << dp->d_name; - - char name[1024]; - std::string dev_path = str.str(); - if (!GetEvdevName(dev_path, name)) - { - //XXX though it also could mean that controller is unusable - cfg.devs.push_back(std::make_pair(dp->d_name, dev_path)); - } - else - { - cfg.devs.push_back(std::make_pair(std::string(name), dev_path)); - } - } - } - } - closedir(dirp); - } - - static void combo_changed(GtkComboBox* widget, gpointer data) - { - gint idx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - ConfigData* cfg = reinterpret_cast(data); - - if (!cfg) - return; - - //std::string& name = (cfg->devs.begin() + idx)->first; - cfg->iter = (cfg->devs.begin() + idx); - - if (idx > 0) - { - } - } - - int GtkHidConfigure(int port, const char* dev_type, HIDType hid_type, GtkWindow* parent) - { - GtkWidget *main_hbox, *right_vbox, *rs_cb; - - assert((int)HIDTYPE_MOUSE == 1); //make sure there is atleast two types so we won't go beyond array length - - ConfigData cfg; - cfg.port = port; - - PopulateHIDs(cfg, hid_type); - cfg.iter = cfg.devs.end(); - - std::string path; - LoadSetting(dev_type, port, APINAME, N_DEVICE, path); - - // --------------------------- - GtkWidget* dlg = gtk_dialog_new_with_buttons( - "HID Evdev Settings", parent, GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE); - gtk_window_set_default_size(GTK_WINDOW(dlg), 320, 240); - - // --------------------------- - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - - main_hbox = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(dlg_area_box), main_hbox); - - // left_vbox = gtk_vbox_new (FALSE, 5); - // gtk_box_pack_start (GTK_BOX (main_hbox), left_vbox, TRUE, TRUE, 5); - right_vbox = gtk_vbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(main_hbox), right_vbox, TRUE, TRUE, 5); - - // --------------------------- - rs_cb = new_combobox("Device:", right_vbox); - - const int evdev_dir_len = strlen(EVDEV_DIR); - int idx = 0, sel_idx = 0; - for (auto& it : cfg.devs) - { - std::stringstream str; - str << it.first; - if (!it.second.empty()) - str << " [" << it.second.substr(evdev_dir_len) << "]"; - - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), str.str().c_str()); - if (!path.empty() && it.second == path) - { - sel_idx = idx; - } - idx++; - } - - //g_object_set_data (G_OBJECT (rs_cb), CFG, &cfg); - g_signal_connect(G_OBJECT(rs_cb), "changed", G_CALLBACK(combo_changed), reinterpret_cast(&cfg)); - gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), sel_idx); - - // --------------------------- - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - - int ret = RESULT_OK; - if (result == GTK_RESPONSE_OK) - { - if (cfg.iter != cfg.devs.end()) - { - if (!SaveSetting(dev_type, port, APINAME, N_DEVICE, cfg.iter->second)) - ret = RESULT_FAILED; - } - } - else - ret = RESULT_CANCELED; - - gtk_widget_destroy(dlg); - return ret; - } - - int EvDev::Configure(int port, const char* dev_type, HIDType hid_type, void* data) - { - return GtkHidConfigure(port, dev_type, hid_type, GTK_WINDOW(data)); - } - -#undef EVDEV_DIR - } // namespace evdev -} // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/evdev/evdev.cpp b/pcsx2/USB/usb-hid/evdev/evdev.cpp deleted file mode 100644 index b151eade8a..0000000000 --- a/pcsx2/USB/usb-hid/evdev/evdev.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "evdev.h" -#include -#include -#include "USB/usb-hid/hidproxy.h" -#include "USB/qemu-usb/input-keymap-linux-to-qcode.h" - -#ifdef USING_X11 -#include -#include -extern Display* g_GSdsp; -extern Window g_GSwin; -#endif - -namespace usb_hid -{ - namespace evdev - { - -#define test_bit(nr, addr) \ - (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) -#define NBITS(x) ((((x)-1) / (sizeof(long) * 8)) + 1) - - bool FindHid(const std::string& evphys, std::string& hid_dev) - { - int fd; - char buf[256]; - - std::stringstream str; - struct dirent* dp; - - DIR* dirp = opendir("/dev/input/"); - if (dirp == NULL) - { - Console.Warning("Error opening /dev/input/"); - return false; - } - - while ((dp = readdir(dirp)) != NULL) - { - if (strncmp(dp->d_name, "hidraw", 6) == 0) - { - - str.clear(); - str.str(""); - str << "/dev/input/" << dp->d_name; - fd = open(str.str().c_str(), O_RDWR | O_NONBLOCK); - - if (fd < 0) - { - Console.Warning("Evdev: Unable to open device: %s", str.str().c_str()); - continue; - } - - memset(buf, 0x0, sizeof(buf)); - //res = ioctl(fd, HIDIOCGRAWNAME(256), buf); - - /* res = ioctl(fd, HIDIOCGRAWPHYS(256), buf); - if (res < 0) - Console.Warning("HIDIOCGRAWPHYS"); - else - */ - close(fd); - if (evphys == buf) - { - closedir(dirp); - hid_dev = str.str(); - return true; - } - } - } - //quit: - closedir(dirp); - return false; - } - - int EvDev::TokenOut(const uint8_t* data, int len) - { - return len; - } - - int EvDev::Open() - { - // Make sure there is atleast two types so we won't go beyond array length - assert((int)HIDTYPE_MOUSE == 1); - std::stringstream name; - - mHandle = -1; - - std::string path; - if (!LoadSetting(mDevType, mPort, APINAME, N_DEVICE, path)) - { - return 1; - } - - if (path.empty() || !file_exists(path)) - goto quit; - - if ((mHandle = open(path.c_str(), O_RDWR | O_NONBLOCK)) < 0) - { - goto quit; - } - - if (!mReaderThreadIsRunning) - { - if (mReaderThread.joinable()) - mReaderThread.join(); - mReaderThread = std::thread(&EvDev::ReaderThread, this); - } - return 0; - - quit: - Close(); - return 1; - } - - int EvDev::Close() - { - if (mHandle != -1) - close(mHandle); - - mHandle = -1; - return 0; - } - - void EvDev::ReaderThread() - { - ssize_t len; - input_event events[32]; - - mReaderThreadIsRunning = true; - - while (mHandle != -1) - { - //Non-blocking read sets len to -1 and errno to EAGAIN if no new data - while ((len = read(mHandle, &events, sizeof(events))) > -1) - { - InputEvent ev{}; - len /= sizeof(events[0]); - for (int i = 0; i < len; i++) - { - input_event& event = events[i]; - switch (event.type) - { - case EV_ABS: - { - - if (mHIDState->kind == HID_MOUSE || mHIDState->kind == HID_KEYBOARD) // usually mouse position is expected to be relative - continue; - - if (!mHIDState->ptr.eh_entry) - continue; - - ev.type = INPUT_EVENT_KIND_ABS; - if (event.code == ABS_X) - { - ev.u.abs.axis = INPUT_AXIS_X; - ev.u.abs.value = event.value; - mHIDState->ptr.eh_entry(mHIDState, &ev); - } - else if (event.code == ABS_Y) - { - ev.u.abs.axis = INPUT_AXIS_Y; - ev.u.abs.value = event.value; - mHIDState->ptr.eh_entry(mHIDState, &ev); - } - } - break; - case EV_REL: - { - if (mHIDState->kind == HID_KEYBOARD || !mHIDState->ptr.eh_entry) - continue; - - ev.type = INPUT_EVENT_KIND_REL; - ev.u.rel.value = event.value; - if (event.code == ABS_X) - { - ev.u.rel.axis = INPUT_AXIS_X; - mHIDState->ptr.eh_entry(mHIDState, &ev); - } - else if (event.code == ABS_Y) - { - ev.u.rel.axis = INPUT_AXIS_Y; - mHIDState->ptr.eh_entry(mHIDState, &ev); - } - } - break; - case EV_KEY: - { - -#ifdef USING_X11 //FIXME not thread-safe - if (event.code == KEY_LEFTSHIFT || event.code == KEY_RIGHTSHIFT) - shift = (event.value > 0); - - if (event.code == KEY_F12 && (event.value == 1) && shift && g_GSdsp) - { - if (!grabbed) - { - grabbed = true; - XGrabPointer(g_GSdsp, g_GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, g_GSwin, None, CurrentTime); - XGrabKeyboard(g_GSdsp, g_GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); - // Hides globally :( - XFixesHideCursor(g_GSdsp, g_GSwin); - } - else - { - grabbed = false; - XUngrabPointer(g_GSdsp, CurrentTime); - XUngrabKeyboard(g_GSdsp, CurrentTime); - XFixesShowCursor(g_GSdsp, g_GSwin); - } - } -#endif - - if (mHIDState->kind == HID_KEYBOARD && mHIDState->kbd.eh_entry) - { - - QKeyCode qcode = Q_KEY_CODE_UNMAPPED; - if (event.code < (uint16_t)qemu_input_map_linux_to_qcode_len) - qcode = qemu_input_map_linux_to_qcode[event.code]; - - if (event.value < 2) - { - ev.type = INPUT_EVENT_KIND_KEY; - ev.u.key.down = (event.value == 1); // 2 if repeat - ev.u.key.key.type = KEY_VALUE_KIND_QCODE; - ev.u.key.key.u.qcode = qcode; - - mHIDState->kbd.eh_entry(mHIDState, &ev); - } - } - - if (mHIDState->kind != HID_KEYBOARD && mHIDState->ptr.eh_entry) - { - ev.type = INPUT_EVENT_KIND_BTN; - switch (event.code) - { - case BTN_LEFT: - ev.u.btn.button = INPUT_BUTTON_LEFT; - ev.u.btn.down = (event.value == 1); - mHIDState->ptr.eh_entry(mHIDState, &ev); - break; - case BTN_RIGHT: - ev.u.btn.button = INPUT_BUTTON_RIGHT; - ev.u.btn.down = (event.value == 1); - mHIDState->ptr.eh_entry(mHIDState, &ev); - break; - case BTN_MIDDLE: - ev.u.btn.button = INPUT_BUTTON_MIDDLE; - ev.u.btn.down = (event.value == 1); - mHIDState->ptr.eh_entry(mHIDState, &ev); - break; - default: - break; - } - } - } - break; - case EV_SYN: //TODO useful? - { - switch (event.code) - { - case SYN_REPORT: - if (mHIDState->ptr.eh_sync) //TODO sync here? - mHIDState->ptr.eh_sync(mHIDState); - break; - case SYN_DROPPED: - //restore last good state - break; - } - } - break; - default: - break; - } - } - - if (len < (ssize_t)sizeof(input_event) && errno != EAGAIN) - { - break; - } - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - mReaderThreadIsRunning = false; - } - - } // namespace evdev -} // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/evdev/evdev.h b/pcsx2/USB/usb-hid/evdev/evdev.h deleted file mode 100644 index aa022d06fc..0000000000 --- a/pcsx2/USB/usb-hid/evdev/evdev.h +++ /dev/null @@ -1,89 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -#include "USB/usb-hid/usb-hid.h" -#include "USB/linux/util.h" -#include "common/Console.h" -#include -#include -#include -#include -#include - -namespace usb_hid -{ - namespace evdev - { - - static const char* APINAME = "evdev"; - - class EvDev : public UsbHID - { - public: - EvDev(int port, const char* dev_type) - : UsbHID(port, dev_type) - , mHandle(-1) - , mReaderThreadIsRunning(false) - { - } - - ~EvDev() { Close(); } - int Open(); - int Close(); - int TokenIn(uint8_t* buf, int len); - int TokenOut(const uint8_t* data, int len); - int Reset() { return 0; } - - static const TCHAR* Name() - { - return TEXT("Evdev"); - } - - static int Configure(int port, const char* dev_type, HIDType hid_type, void* data); - - protected: - void ReaderThread(); - - int mHandle; - - std::thread mReaderThread; - std::atomic mReaderThreadIsRunning; - }; - - template - bool GetEvdevName(const std::string& path, char (&name)[_Size]) - { - int fd = 0; - if ((fd = open(path.c_str(), O_RDONLY)) < 0) - { - Console.Warning("Cannot open %s\n", path.c_str()); - } - else - { - if (ioctl(fd, EVIOCGNAME(_Size), name) < -1) - { - Console.Warning("Cannot get controller's name\n"); - close(fd); - return false; - } - close(fd); - return true; - } - return false; - } - - } // namespace evdev -} // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/hidproxy.h b/pcsx2/USB/usb-hid/hidproxy.h deleted file mode 100644 index 08ae7673b5..0000000000 --- a/pcsx2/USB/usb-hid/hidproxy.h +++ /dev/null @@ -1,93 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef USBHIDPROXY_H -#define USBHIDPROXY_H -#include -#include -#include -#include -#include -#include "usb-hid.h" -#include "USB/helpers.h" -#include "USB/deviceproxy.h" - -namespace usb_hid -{ - - class UsbHIDError : public std::runtime_error - { - public: - UsbHIDError(const char* msg) - : std::runtime_error(msg) - { - } - virtual ~UsbHIDError() throw() {} - }; - - class UsbHIDProxyBase : public ProxyBase - { - UsbHIDProxyBase(const UsbHIDProxyBase&) = delete; - - public: - UsbHIDProxyBase() {} - UsbHIDProxyBase(const std::string& name); - virtual UsbHID* CreateObject(int port, const char* dev_type) const = 0; - // ProxyBase::Configure is ignored - virtual int Configure(int port, const char* dev_type, void* data) { return RESULT_CANCELED; } - virtual int Configure(int port, const char* dev_type, HIDType hid_type, void* data) = 0; - }; - - template - class UsbHIDProxy : public UsbHIDProxyBase - { - UsbHIDProxy(const UsbHIDProxy&) = delete; - - public: - UsbHIDProxy() {} - UsbHIDProxy(const std::string& name) - : UsbHIDProxyBase(name) - { - } - UsbHID* CreateObject(int port, const char* dev_type) const - { - try - { - return new T(port, dev_type); - } - catch (UsbHIDError& err) - { - (void)err; - return nullptr; - } - } - virtual const TCHAR* Name() const - { - return T::Name(); - } - virtual int Configure(int port, const char* dev_type, HIDType hid_type, void* data) - { - return T::Configure(port, dev_type, hid_type, data); - } - }; - - class RegisterUsbHID : public RegisterProxy - { - public: - static void Register(); - }; - -} // namespace usb_hid -#endif diff --git a/pcsx2/USB/usb-hid/noop.h b/pcsx2/USB/usb-hid/noop.h deleted file mode 100644 index ee25a86f96..0000000000 --- a/pcsx2/USB/usb-hid/noop.h +++ /dev/null @@ -1,52 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "usb-hid.h" -#include "hidproxy.h" - -namespace usb_hid -{ - namespace noop - { - - static const char* APINAME = "noop"; - - class NOOP : public UsbHID - { - public: - NOOP(int port, const char* dev_type) - : UsbHID(port, dev_type) - { - } - ~NOOP() {} - int Open() { return 0; } - int Close() { return 0; } - int TokenIn(uint8_t* buf, int len) { return len; } - int TokenOut(const uint8_t* data, int len) { return len; } - int Reset() { return 0; } - - static const TCHAR* Name() - { - return TEXT("NOOP"); - } - - static int Configure(int port, const char* dev_type, HIDType type, void* data) - { - return RESULT_CANCELED; - } - }; - - } // namespace noop -} // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/raw/rawinput.cpp b/pcsx2/USB/usb-hid/raw/rawinput.cpp deleted file mode 100644 index 26c7d398cc..0000000000 --- a/pcsx2/USB/usb-hid/raw/rawinput.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "rawinput.h" -#include "USB/Win32/Config_usb.h" -#include "USB/qemu-usb/input-keymap.h" -#include "USB/qemu-usb/input-keymap-win32-to-qcode.h" - -namespace usb_hid -{ - namespace raw - { - -#define CHECK(exp) \ - do \ - { \ - if (!(exp)) \ - goto Error; \ - } while (0) -#define SAFE_FREE(p) \ - do \ - { \ - if (p) \ - { \ - free(p); \ - (p) = NULL; \ - } \ - } while (0) - - // VKEY from https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes - // and convert to HID usage id from "10 Keyboard/Keypad Page (0x07)" - // https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf - - int RawInput::TokenOut(const uint8_t* data, int len) - { - // std::array report{ 0 }; - // memcpy(report.data() + 1, data, report.size() - 1); - - return len; - } - - static void ParseRawInput(PRAWINPUT pRawInput, HIDState* hs) - { - PHIDP_PREPARSED_DATA pPreparsedData = NULL; - HIDP_CAPS Caps; - PHIDP_BUTTON_CAPS pButtonCaps = NULL; - PHIDP_VALUE_CAPS pValueCaps = NULL; - UINT bufferSize = 0; - ULONG usageLength, value; - TCHAR name[1024] = {0}; - UINT nameSize = 1024; - RID_DEVICE_INFO devInfo = {0}; - std::wstring devName; - USHORT capsLength = 0; - USAGE usage[32] = {0}; - int numberOfButtons; - - GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, name, &nameSize); - - devName = name; - std::transform(devName.begin(), devName.end(), devName.begin(), ::toupper); - - CHECK(GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0); - CHECK(pPreparsedData = (PHIDP_PREPARSED_DATA)malloc(bufferSize)); - CHECK((int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0); - CHECK(HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS); - - //Get pressed buttons - CHECK(pButtonCaps = (PHIDP_BUTTON_CAPS)malloc(sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps)); - //If fails, maybe wheel only has axes - capsLength = Caps.NumberInputButtonCaps; - HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData); - - numberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1; - usageLength = countof(usage); //numberOfButtons; - - NTSTATUS stat; - if ((stat = HidP_GetUsages( - HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData, - (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid)) == HIDP_STATUS_SUCCESS) - { - for (uint32_t i = 0; i < usageLength; i++) - { - uint16_t btn = usage[i] - pButtonCaps->Range.UsageMin; - } - } - - /// Get axes' values - CHECK(pValueCaps = (PHIDP_VALUE_CAPS)malloc(sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps)); - capsLength = Caps.NumberInputValueCaps; - if (HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS) - { - for (USHORT i = 0; i < capsLength; i++) - { - if (HidP_GetUsageValue( - HidP_Input, pValueCaps[i].UsagePage, 0, - pValueCaps[i].Range.UsageMin, &value, pPreparsedData, - (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) - { - continue; // if here then maybe something is up with HIDP_CAPS.NumberInputValueCaps - } - - switch (pValueCaps[i].Range.UsageMin) - { - case HID_USAGE_GENERIC_X: //0x30 - case HID_USAGE_GENERIC_Y: - case HID_USAGE_GENERIC_Z: - case HID_USAGE_GENERIC_RX: - case HID_USAGE_GENERIC_RY: - case HID_USAGE_GENERIC_RZ: //0x35 - //int axis = (value * 0x3FFF) / pValueCaps[i].LogicalMax; - break; - case HID_USAGE_GENERIC_HATSWITCH: - //Console.Warning("Hat: %02X\n", value); - break; - } - } - } - - Error: - SAFE_FREE(pPreparsedData); - SAFE_FREE(pButtonCaps); - SAFE_FREE(pValueCaps); - } - - static void ParseRawInputKB(RAWKEYBOARD& k, HIDState* hs) - { - if (hs->kind != HID_KEYBOARD || !hs->kbd.eh_entry) - return; - - if (KEYBOARD_OVERRUN_MAKE_CODE == k.MakeCode) - return; - - QKeyCode qcode = Q_KEY_CODE_UNMAPPED; - if (k.VKey < (int)qemu_input_map_win32_to_qcode.size()) - qcode = qemu_input_map_win32_to_qcode[k.VKey]; - - //TODO - if (k.Flags & RI_KEY_E0) - { - if (Q_KEY_CODE_SHIFT == qcode) - qcode = Q_KEY_CODE_SHIFT_R; - else if (Q_KEY_CODE_CTRL == qcode) - qcode = Q_KEY_CODE_CTRL_R; - else if (Q_KEY_CODE_ALT == qcode) - qcode = Q_KEY_CODE_ALT_R; - } - - InputEvent ev{}; - ev.type = INPUT_EVENT_KIND_KEY; - ev.u.key.down = !(k.Flags & RI_KEY_BREAK); - ev.u.key.key.type = KEY_VALUE_KIND_QCODE; - ev.u.key.key.u.qcode = qcode; - - hs->kbd.eh_entry(hs, &ev); - } - - static void SendPointerEvent(InputEvent& ev, HIDState* hs) - { - hs->ptr.eh_entry(hs, &ev); - } - - static void ParseRawInputMS(RAWMOUSE& m, HIDState* hs) - { - if (!hs->ptr.eh_entry || (hs->kind != HID_MOUSE && hs->kind != HID_TABLET)) - return; - - int z = 0; - InputEvent ev{}; - - if (m.usButtonFlags & RI_MOUSE_WHEEL) - z = (short)m.usButtonData / WHEEL_DELTA; - - ev.type = INPUT_EVENT_KIND_BTN; - - if (m.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN) - { - ev.u.btn.button = INPUT_BUTTON_LEFT; - ev.u.btn.down = true; - SendPointerEvent(ev, hs); - } - if (m.ulButtons & RI_MOUSE_LEFT_BUTTON_UP) - { - ev.u.btn.button = INPUT_BUTTON_LEFT; - ev.u.btn.down = false; - SendPointerEvent(ev, hs); - } - - if (m.ulButtons & RI_MOUSE_RIGHT_BUTTON_DOWN) - { - ev.u.btn.button = INPUT_BUTTON_RIGHT; - ev.u.btn.down = true; - SendPointerEvent(ev, hs); - } - if (m.ulButtons & RI_MOUSE_RIGHT_BUTTON_UP) - { - ev.u.btn.button = INPUT_BUTTON_RIGHT; - ev.u.btn.down = false; - SendPointerEvent(ev, hs); - } - - if (m.ulButtons & RI_MOUSE_MIDDLE_BUTTON_DOWN) - { - ev.u.btn.button = INPUT_BUTTON_MIDDLE; - ev.u.btn.down = true; - SendPointerEvent(ev, hs); - } - if (m.ulButtons & RI_MOUSE_MIDDLE_BUTTON_UP) - { - ev.u.btn.button = INPUT_BUTTON_MIDDLE; - ev.u.btn.down = false; - SendPointerEvent(ev, hs); - } - - if (z != 0) - { - ev.u.btn.button = (z < 0) ? INPUT_BUTTON_WHEEL_DOWN : INPUT_BUTTON_WHEEL_UP; - for (int i = 0; i < z; i++) - { - ev.u.btn.down = true; - SendPointerEvent(ev, hs); - ev.u.btn.down = false; // TODO needs an UP event? - SendPointerEvent(ev, hs); - } - } - - if (m.usFlags & MOUSE_MOVE_ABSOLUTE) - { - /*ev.type = INPUT_EVENT_KIND_ABS; - ev.u.abs.axis = INPUT_AXIS_X; - ev.u.abs.value = m.lLastX; - SendPointerEvent(ev, hs); - - ev.u.abs.axis = INPUT_AXIS_Y; - ev.u.abs.value = m.lLastY; - SendPointerEvent(ev, hs);*/ - } - else - { - ev.type = INPUT_EVENT_KIND_REL; - ev.u.rel.axis = INPUT_AXIS_X; - ev.u.rel.value = m.lLastX; - SendPointerEvent(ev, hs); - - ev.u.rel.axis = INPUT_AXIS_Y; - ev.u.rel.value = m.lLastY; - SendPointerEvent(ev, hs); - } - - - if (hs->ptr.eh_sync) - hs->ptr.eh_sync(hs); - } - - void RawInput::ParseRawInput(PRAWINPUT pRawInput) - { - if (pRawInput->header.dwType == RIM_TYPEKEYBOARD) - ParseRawInputKB(pRawInput->data.keyboard, mHIDState); - else if (pRawInput->header.dwType == RIM_TYPEMOUSE) - ParseRawInputMS(pRawInput->data.mouse, mHIDState); - // else - // ParseRawInput(pRawInput, mHIDState); - } - - int RawInput::Open() - { - Close(); - shared::rawinput::RegisterCallback(this); - return 0; - } - - int RawInput::Close() - { - shared::rawinput::UnregisterCallback(this); - Reset(); - return 0; - } - - int RawInput::Configure(int port, const char* dev_type, HIDType type, void* data) - { - Win32Handles* h = (Win32Handles*)data; - INT_PTR res = RESULT_CANCELED; - return res; - } - - } // namespace raw -} // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/raw/rawinput.h b/pcsx2/USB/usb-hid/raw/rawinput.h deleted file mode 100644 index 5d3199d9a0..0000000000 --- a/pcsx2/USB/usb-hid/raw/rawinput.h +++ /dev/null @@ -1,54 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "USB/shared/rawinput_usb.h" -#include "USB/usb-hid/hidproxy.h" -#include "USB/usb-hid/usb-hid.h" - -namespace usb_hid -{ - namespace raw - { - - static const char* APINAME = "rawinput"; - - class RawInput : public UsbHID, shared::rawinput::ParseRawInputCB - { - public: - RawInput(int port, const char* dev_type) - : UsbHID(port, dev_type) - { - } - ~RawInput() - { - Close(); - } - int Open(); - int Close(); - // int TokenIn(uint8_t *buf, int len); - int TokenOut(const uint8_t* data, int len); - int Reset() { return 0; } - void ParseRawInput(PRAWINPUT pRawInput); - - static const TCHAR* Name() - { - return TEXT("Raw Input"); - } - - static int Configure(int port, const char* dev_type, HIDType, void* data); - }; - - } // namespace raw -} // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/usb-buzzer.cpp b/pcsx2/USB/usb-hid/usb-buzzer.cpp deleted file mode 100644 index 6edfb42146..0000000000 --- a/pcsx2/USB/usb-hid/usb-buzzer.cpp +++ /dev/null @@ -1,936 +0,0 @@ -/* - * QEMU USB HID devices - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -#include -#include -extern "C" { -#include "USB/ddk/hidsdi.h" -} - -#pragma comment(lib, "setupapi.lib") -#pragma comment(lib, "ddk/hid.lib") - -#if 0 -/* HID interface requests */ -#define GET_REPORT 0xa101 -#define GET_IDLE 0xa102 -#define GET_PROTOCOL 0xa103 -#define SET_IDLE 0x210a -#define SET_PROTOCOL 0x210b - -#define USB_MOUSE 1 -#define USB_TABLET 2 - -typedef struct USBKeyboardState { - USBDevice dev; - int keyboard_grabbed; -} USBKeyboardState; - -extern HWND gsWnd; - -#define VK_BASED - -#ifdef VK_BASED -static const uint8_t vk_to_key_code[] = { -0x00, //FAIL: 0x00 -0x00, //FAIL: LMOUSE -0x00, //FAIL: RMOUSE -0x00, //FAIL: Break -0x00, //FAIL: MMOUSE -0x00, //FAIL: X1MOUSE -0x00, //FAIL: X2MOUSE -0x00, //FAIL: 0x00 -0x2A, //OK: Backspace -0x2B, //OK: Tab -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x9C, //OK: Clear -0x28, //FAIL: ENTER -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: SHIFT -0x00, //FAIL: CTRL -0x00, //FAIL: ALT -0x48, //OK: Pause -0x39, //OK: Caps Lock -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -//0x00, //FAIL: 0x00 -//0x00, //FAIL: 0x00 -//0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x29, //FAIL: ESC -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x2C, //OK: Spacebar -#ifdef ENABLE_KEYPAD_Fx -0x4B, //FAIL: PAGE UP -0x4E, //FAIL: PAGE DOWN -0x4D, //OK: End -0x4A, //OK: Home -0x50, //FAIL: LEFT ARROW -0x52, //FAIL: UP ARROW -0x4F, //FAIL: RIGHT ARROW -0x51, //FAIL: DOWN ARROW -0x77, //OK: Select -0x00, //FAIL: PRINT -0x74, //OK: Execute -0x46, //FAIL: PRINT SCREEN -0x49, //FAIL: INS -0x4C, //FAIL: DEL -0x75, //OK: Help VK_HOME -#else -0x00, //FAIL: PAGE UP -0x00, //FAIL: PAGE DOWN -0x00, //OK: End -0x00, //OK: Home -0x00, //FAIL: LEFT ARROW -0x00, //FAIL: UP ARROW -0x00, //FAIL: RIGHT ARROW -0x00, //FAIL: DOWN ARROW -0x00, //OK: Select -0x00, //FAIL: PRINT -0x00, //OK: Execute -0x00, //FAIL: PRINT SCREEN -0x00, //FAIL: INS -0x00, //FAIL: DEL -0x00, //OK: Help VK_HOME -#endif -0x27, //OK: 0 -0x1E, //OK: 1 -0x1F, //OK: 2 -0x20, //OK: 3 -0x21, //OK: 4 -0x22, //OK: 5 -0x23, //OK: 6 -0x24, //OK: 7 -0x25, //OK: 8 -0x26, //OK: 9 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: not found -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x04, //OK: A -0x05, //OK: B -0x06, //OK: C -0x07, //OK: D -0x08, //OK: E -0x09, //OK: F -0x0A, //OK: G -0x0B, //OK: H -0x0C, //OK: I -0x0D, //OK: J -0x0E, //OK: K -0x0F, //OK: L -0x10, //OK: M -0x11, //OK: N -0x12, //OK: O -0x13, //OK: P -0x14, //OK: Q -0x15, //OK: R -0x16, //OK: S -0x17, //OK: T -0x18, //OK: U -0x19, //OK: V -0x1A, //OK: W -0x1B, //OK: X -0x1C, //OK: Y -0x1D, //OK: Z -#ifdef ENABLE_KEYPAD_Fx -0xE3, //OK: LGUI -0xE7, //OK: RGUI -0x65, //OK: Application -0x00, //FAIL: 0x00 -0x00, //FAIL: SLEEP -0x62, //OK: Keypad 0 -0x59, //OK: Keypad 1 -0x5A, //OK: Keypad 2 -0x5B, //OK: Keypad 3 -0x5C, //OK: Keypad 4 -0x5D, //OK: Keypad 5 -0x5E, //OK: Keypad 6 -0x5F, //OK: Keypad 7 -0x60, //OK: Keypad 8 -0x61, //OK: Keypad 9 -0x55, //OK: Keypad * -0x57, //OK: Keypad + -0x9F, //OK: Separator -0x56, //OK: Keypad - -0x63, //OK: Keypad . -0x54, //OK: Keypad / -0x3A, //OK: F1 -0x3B, //OK: F2 -0x3C, //OK: F3 -0x3D, //OK: F4 -0x3E, //OK: F5 -0x3F, //OK: F6 -0x40, //OK: F7 -0x41, //OK: F8 -0x42, //OK: F9 -0x43, //OK: F10 -0x44, //OK: F11 -0x45, //OK: F12 -0x68, //OK: F13 -0x69, //OK: F14 -0x6A, //OK: F15 -0x6B, //OK: F16 -0x6C, //OK: F17 -0x6D, //OK: F18 -0x6E, //OK: F19 -0x6F, //OK: F20 -0x70, //OK: F21 -0x71, //OK: F22 -0x72, //OK: F23 -0x73, //OK: F24 -#else -0x00, //OK: LGUI -0x00, //OK: RGUI -0x00, //OK: Application -0x00, //FAIL: 0x00 -0x00, //FAIL: SLEEP -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00, -#endif -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x83, //OK: NUM LOCK -0x47, //OK: Scroll Lock -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0xE1, //OK: LSHIFT -0xE5, //OK: RSHIFT -0xE0, //OK: LCONTROL -0xE4, //OK: RCONTROL -0xE3, //OK: LGUI -0xE7, //OK: RGUI -0x00, //FAIL: Windows 2000/XP: Browser Back -0x00, //FAIL: Windows 2000/XP: Browser Forward -0x00, //FAIL: Windows 2000/XP: Browser Refresh -0x00, //FAIL: Windows 2000/XP: Browser Stop -0x00, //FAIL: Windows 2000/XP: Browser Search -0x00, //FAIL: Windows 2000/XP: Browser Favorites -0x00, //FAIL: Windows 2000/XP: Browser Start and Home -0x00, //FAIL: Windows 2000/XP: Volume Mute -0x00, //FAIL: Windows 2000/XP: Volume Down -0x00, //FAIL: Windows 2000/XP: Volume Up -0x00, //FAIL: Windows 2000/XP: Next Track -0x00, //FAIL: Windows 2000/XP: Previous Track -0x00, //FAIL: Windows 2000/XP: Stop Media -0x00, //FAIL: Windows 2000/XP: Play/Pause Media -0x00, //FAIL: Windows 2000/XP: Start Mail -0x00, //FAIL: Windows 2000/XP: Select Media -0x00, //FAIL: Windows 2000/XP: Start Application 1 -0x00, //FAIL: Windows 2000/XP: Start Application 2 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x33, //FAIL: Windows 2000/XP: For the US standard keyboard, the ';:' key -0x2E, //FAIL: Windows 2000/XP: For any country/region, the '+' -0x36, //FAIL: Windows 2000/XP: For any country/region, the ',' -0x2D, //FAIL: Windows 2000/XP: For any country/region, the '-' -0x37, //FAIL: Windows 2000/XP: For any country/region, the '.' -0x38, //FAIL: Windows 2000/XP: For the US standard keyboard, the '/?' key -0x35, //FAIL: Windows 2000/XP: For the US standard keyboard, the '`~' key -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: not found -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x2F, //FAIL: Windows 2000/XP: For the US standard keyboard, the '[{' key -0x31, //FAIL: Windows 2000/XP: For the US standard keyboard, the '\|' key -0x30, //FAIL: Windows 2000/XP: For the US standard keyboard, the ']}' key -0x34, //FAIL: Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key -0x00, //FAIL: Used for miscellaneous characters; it can vary byboard. -0x00, //FAIL: Reserved -0x00, //FAIL: OEM specific -0x32, //FAIL: Windows 2000/XP: Either the angle bracket or the backslash key on the RT 102-key keyboard -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCEE6 -0x00, //FAIL: OEM specific -0x00, //FAIL: Windows 2000/XP: Used to pass Unicode characters as if they E8 -0x00, //FAIL: Unassigned -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: 0x00 -0x00, //FAIL: Attn -0xA3, //OK: CrSel -0xA4, //OK: ExSel -0x00, //FAIL: Erase EOF -0x00, //FAIL: Play -0x00, //FAIL: Zoom -0x00, //FAIL: Reserved -0x00, //FAIL: PA1 -0x9C, //OK: Clear -0x00, //FAIL: 0x00 -}; -#else -#ifdef ENABLE_KEYPAD_Fx -static const unsigned char scan_to_usb[] = { -0x00,0x29,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x2f,0x30,0x2a,0x2b, -0x14,0x1a,0x08,0x15,0x17,0x1c,0x18,0x0c,0x12,0x13,0x33,0x2e,0x28,0xe0,0x04,0x16, -0x07,0x09,0x0a,0x0b,0x0d,0x0e,0x0f,0x35,0x34,0x31,0xe1,0x38,0x1d,0x1b,0x06,0x19, -0x05,0x11,0x10,0x36,0x37,0x2d,0xe5,0x55,0xe3,0x2c,0x39,0x3a,0x3b,0x3c,0x3d,0x3e, -0x3f,0x40,0x41,0x42,0x43,0x83,0x47,0x5f,0x60,0x61,0x56,0x5c,0x5d,0x5e,0x57,0x59, -0x5a,0x5b,0x62,0x63,0x46,0x00,0x32,0x44,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x75,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x54,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xe7,0x65,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -#else -static const unsigned char scan_to_usb[] = { -0x00,0x29,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x2f,0x30,0x2a,0x2b, -0x14,0x1a,0x08,0x15,0x17,0x1c,0x18,0x0c,0x12,0x13,0x33,0x2e,0x28,0xe0,0x04,0x16, -0x07,0x09,0x0a,0x0b,0x0d,0x0e,0x0f,0x35,0x34,0x31,0xe1,0x38,0x1d,0x1b,0x06,0x19, -0x05,0x11,0x10,0x36,0x37,0x2d,0xe5,0x00,0xe3,0x2c,0x39,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x83,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x46,0x00,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xe7,0x65,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -#endif -#endif - -/* mostly the same values as the Bochs USB Keyboard device */ -static const uint8_t qemu_keyboard_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x00, /* u16 bcdUSB; v1.0 */ - - 0x00, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - -// 0x27, 0x06, /* u16 idVendor; */ - 0x4C, 0x05, - // 0x01, 0x00, /* u16 idProduct; */ - 0x00, 0x10, - 0x00, 0x00, /* u16 bcdDevice */ - - 0x03, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x01, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ -}; - -static const uint8_t qemu_keyboard_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 50, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x03, /* u8 if_bInterfaceClass; */ - 0x01, /* u8 if_bInterfaceSubClass; */ - 0x01, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x05, /* u8 if_iInterface; */ - - /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ - 0x01, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 50, 0, /* u16 len */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const uint8_t qemu_tablet_config_descriptor[] = { - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 50, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x03, /* u8 if_bInterfaceClass; */ - 0x01, /* u8 if_bInterfaceSubClass; */ - 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x05, /* u8 if_iInterface; */ - - /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ - 0x03, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 74, 0, /* u16 len */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const uint8_t qemu_keyboard_hid_report_descriptor[] = { - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard Left Control) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x95, 0x05, // REPORT_COUNT (5) - 0x75, 0x01, // REPORT_SIZE (1) - 0x05, 0x08, // USAGE_PAGE (LEDs) - 0x19, 0x01, // USAGE_MINIMUM (Num Lock) - 0x29, 0x05, // USAGE_MAXIMUM (Kana) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x03, // REPORT_SIZE (3) - 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) - 0x95, 0x06, // REPORT_COUNT (6) - 0x75, 0x08, // REPORT_SIZE (8) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0 // END_COLLECTION -}; - -#define BUZZER_VID 0x054C -#define BUZZER_PID 0x1000 -#define BUZZER_PID2 0x0002 - -unsigned char comp_data[6]; -HANDLE usb_buzzer=(HANDLE)-1; -HANDLE readData=(HANDLE)-1; -OVERLAPPED ovl; - -static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len) -{ - unsigned char data[6]; - - ReadFile(usb_buzzer, data, 6, 0, &ovl); - - if(!memcmp(data, comp_data, 6) || (data[0]!=0x00 && data[1]!=0x7F && data[2]!=0x7F)){ - //No event from buzzers - // CancelIo(usb_buzzer); - return USB_RET_STALL; - }else{ - //We got an event !!! - memset(buf, 0, 6); - memcpy(comp_data, data, 6); - - buf[0]=0x7F; - buf[1]=0x7F; - buf[2]=data[3]; - buf[3]=data[4]; - buf[4]=data[5]|0xF0; - - return 16; - } - - return 16; -} - -static void usb_keyboard_handle_reset(USBDevice *dev) -{ - USBKeyboardState *s = (USBKeyboardState *)dev; -} - -static int usb_keyboard_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) -{ - USBKeyboardState *s = (USBKeyboardState *)dev; - int ret = 0; - unsigned char buf[8]; - - switch(request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_keyboard_dev_descriptor, - sizeof(qemu_keyboard_dev_descriptor)); - ret = sizeof(qemu_keyboard_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_keyboard_config_descriptor, - sizeof(qemu_keyboard_config_descriptor)); - ret = sizeof(qemu_keyboard_config_descriptor); - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* serial number */ - ret = set_usb_string(data, "1"); - break; - case 2: - /* product description */ - ret = set_usb_string(data, "Generic USB Keyboard"); - break; - case 3: - /* vendor description */ - ret = set_usb_string(data, "PCSX2/QEMU"); - break; - case 4: - ret = set_usb_string(data, "HID Keyboard"); - break; - case 5: - ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; - /* hid specific requests */ - case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case 0x22: - memcpy(data, qemu_keyboard_hid_report_descriptor, - sizeof(qemu_keyboard_hid_report_descriptor)); - ret = sizeof(qemu_keyboard_hid_report_descriptor); - break; - default: - goto fail; - } - break; - case GET_REPORT: - ret = usb_keyboard_poll(s, data, length); - break; - case 0x2109: - ret=0; - memset(buf, 0, 8); - buf[2]=data[1]; - buf[3]=data[2]; - buf[4]=data[3]; - buf[5]=data[4]; - CancelIo(usb_buzzer); - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - break; - case SET_IDLE: - ret = 0; - break; - default: - fail: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static int usb_keyboard_handle_data(USBDevice *dev, int pid, - uint8_t devep, uint8_t *data, int len) -{ - USBKeyboardState *s = (USBKeyboardState *)dev; - int ret = 0; - unsigned char buf[8]; - - switch(pid) { - case USB_TOKEN_IN: - if (devep == 1) { - ret = usb_keyboard_poll(s, data, len); - } else { - goto fail; - } - break; - case USB_TOKEN_OUT: - ret=0; - memset(buf, 0, 8); - buf[2]=data[1]; - buf[3]=data[2]; - buf[4]=data[3]; - buf[5]=data[4]; - CancelIo(usb_buzzer); - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - break; - default: - fail: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static void usb_keyboard_handle_destroy(USBDevice *dev) -{ - USBKeyboardState *s = (USBKeyboardState *)dev; - - //qemu_add_keyboard_event_handler(NULL, NULL, 0); - free(s); - CloseHandle(usb_buzzer); -} - -USBDevice *usb_keyboard_init(void) -{ - USBKeyboardState *s; - - s = (USBKeyboardState *)malloc(sizeof(USBKeyboardState)); - if (!s) - return NULL; - memset(s,0,sizeof(USBKeyboardState)); - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; - - s->dev.handle_reset = usb_keyboard_handle_reset; - s->dev.handle_control = usb_keyboard_handle_control; - s->dev.handle_data = usb_keyboard_handle_data; - s->dev.handle_destroy = usb_keyboard_handle_destroy; - - strncpy(s->dev.devname, "Generic USB Keyboard", sizeof(s->dev.devname)); - - int i=0; - DWORD needed=0; - unsigned char buf[8]; - HDEVINFO devInfo; - GUID guid; - SP_DEVICE_INTERFACE_DATA diData; - PSP_DEVICE_INTERFACE_DETAIL_DATA didData; - HIDD_ATTRIBUTES attr; - - readData=CreateEvent(0, 0, 0, 0); - memset(&ovl, 0, sizeof(OVERLAPPED)); - ovl.hEvent=readData; - ovl.Offset=0; - ovl.OffsetHigh=0; - - HidD_GetHidGuid(&guid); - - devInfo=SetupDiGetClassDevs(&guid, 0, 0, DIGCF_DEVICEINTERFACE); - if(!devInfo)return 0; - - diData.cbSize=sizeof(diData); - - while(SetupDiEnumDeviceInterfaces(devInfo, 0, &guid, i, &diData)){ - if(usb_buzzer!=INVALID_HANDLE_VALUE)CloseHandle(usb_buzzer); - - SetupDiGetDeviceInterfaceDetail(devInfo, &diData, 0, 0, &needed, 0); - - didData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(needed); - didData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if(!SetupDiGetDeviceInterfaceDetail(devInfo, &diData, didData, needed, 0, 0)){ - free(didData); - break; - } - - usb_buzzer=CreateFile(didData->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if(usb_buzzer==INVALID_HANDLE_VALUE){ - free(didData); - i++; - continue; - } - - HidD_GetAttributes(usb_buzzer, &attr); - - - if((attr.VendorID==BUZZER_VID) && (attr.ProductID==BUZZER_PID || attr.ProductID==BUZZER_PID2)){ - //We've found our buzzers !!! - free(didData); - - memset(buf, 0, 8); - buf[2]=0xFF; - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - Sleep(100); - - memset(buf, 0, 8); - buf[3]=0xFF; - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - Sleep(100); - - memset(buf, 0, 8); - buf[4]=0xFF; - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - Sleep(100); - - memset(buf, 0, 8); - buf[5]=0xFF; - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - Sleep(100); - - memset(buf, 0, 8); - WriteFile(usb_buzzer, buf, 8, 0, &ovl); - break; - } - i++; - } - - return (USBDevice *)s; -} -#endif diff --git a/pcsx2/USB/usb-hid/usb-hid.cpp b/pcsx2/USB/usb-hid/usb-hid.cpp index ed5895dc7c..3af198e5fb 100644 --- a/pcsx2/USB/usb-hid/usb-hid.cpp +++ b/pcsx2/USB/usb-hid/usb-hid.cpp @@ -25,71 +25,37 @@ #include "PrecompiledHeader.h" #include "USB/deviceproxy.h" -#include "hidproxy.h" #include "USB/qemu-usb/desc.h" +#include "USB/qemu-usb/USBinternal.h" #include "usb-hid.h" -#include "USB/shared/inifile_usb.h" +#include "USB/USB.h" +#include "StateWrapper.h" -#define CONTAINER_OF(p, type, field) ((type*)((char*)p - ((ptrdiff_t) & ((type*)0)->field))) +#include "Frontend/InputManager.h" namespace usb_hid { - - typedef struct UsbHIDState + struct UsbHIDState { - USBDevice dev; - USBDesc desc; - USBDescDevice desc_dev; + explicit UsbHIDState(u32 port_); - UsbHID* usbhid; + USBDevice dev{}; + USBDesc desc{}; + USBDescDevice desc_dev{}; - USBEndpoint* intr; - uint8_t port; - struct freeze - { - HIDState hid; - int ep; - } f; + USBEndpoint* intr = nullptr; + HIDState hid{}; - } UsbHIDState; + u32 port = 0; - std::list HIDKbdDevice::ListAPIs() - { - return RegisterUsbHID::instance().Names(); - } + std::map keycode_mapping; - const TCHAR* HIDKbdDevice::LongAPIName(const std::string& name) - { - auto proxy = RegisterUsbHID::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } + void SetKeycodeMapping(); - std::list BeatManiaDevice::ListAPIs() - { - return RegisterUsbHID::instance().Names(); - } - - const TCHAR* BeatManiaDevice::LongAPIName(const std::string& name) - { - auto proxy = RegisterUsbHID::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } - std::list HIDMouseDevice::ListAPIs() - { - return RegisterUsbHID::instance().Names(); - } - - const TCHAR* HIDMouseDevice::LongAPIName(const std::string& name) - { - auto proxy = RegisterUsbHID::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } + void QueueKeyboardState(KeyValue keycode, bool pressed); + void QueueMouseAxisState(InputPointerAxis axis, float delta); + void QueueMouseButtonState(InputButton button, bool pressed); + }; enum { @@ -124,8 +90,8 @@ namespace usb_hid /* mostly the same values as the Bochs USB Keyboard device */ static const uint8_t kbd_dev_desc[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ 0x10, 0x00, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ @@ -139,26 +105,26 @@ namespace usb_hid 0x00, 0x10, 0x00, 0x00, /* u16 bcdDevice */ - STR_MANUFACTURER, /* u8 iManufacturer; */ + STR_MANUFACTURER, /* u8 iManufacturer; */ STR_PRODUCT_KEYBOARD, /* u8 iProduct; */ - STR_SERIALNUMBER, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ + STR_SERIALNUMBER, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ }; static const uint8_t kbd_config_desc[] = { /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ - 50, /* u8 MaxPower; */ + 50, /* u8 MaxPower; */ /* USB 1.1: * USB 2.0, single TT organization (mandatory): @@ -183,27 +149,27 @@ namespace usb_hid 0x05, /* u8 if_iInterface; */ /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ 0x01, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 63, 0, /* u16 len */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 63, 0, /* u16 len */ /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; /* mostly the same values as the Bochs USB Mouse device */ static const uint8_t qemu_mouse_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ 0x10, 0x00, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ @@ -215,26 +181,26 @@ namespace usb_hid 0x01, 0x00, /* u16 idProduct; */ 0x00, 0x00, /* u16 bcdDevice */ - STR_MANUFACTURER, /* u8 iManufacturer; */ + STR_MANUFACTURER, /* u8 iManufacturer; */ STR_PRODUCT_MOUSE, /* u8 iProduct; */ - STR_SERIALNUMBER, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ + STR_SERIALNUMBER, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ }; static const uint8_t qemu_mouse_config_descriptor[] = { /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ - 50, /* u8 MaxPower; */ + 50, /* u8 MaxPower; */ /* USB 1.1: * USB 2.0, single TT organization (mandatory): @@ -259,37 +225,37 @@ namespace usb_hid 0x05, /* u8 if_iInterface; */ /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ 0x01, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 52, 0, /* u16 len */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 52, 0, /* u16 len */ /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x04, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; - [[maybe_unused]]static const uint8_t qemu_tablet_config_descriptor[] = { + [[maybe_unused]] static const uint8_t qemu_tablet_config_descriptor[] = { /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ 0x22, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ - 50, /* u8 MaxPower; */ + 50, /* u8 MaxPower; */ /* USB 1.1: * USB 2.0, single TT organization (mandatory): @@ -314,21 +280,21 @@ namespace usb_hid 0x05, /* u8 if_iInterface; */ /* HID descriptor */ - 0x09, /* u8 bLength; */ - 0x21, /* u8 bDescriptorType; */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ 0x01, 0x00, /* u16 HID_class */ - 0x00, /* u8 country_code */ - 0x01, /* u8 num_descriptors */ - 0x22, /* u8 type; Report */ - 74, 0, /* u16 len */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 74, 0, /* u16 len */ /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { @@ -357,48 +323,48 @@ namespace usb_hid 0x75, 0x08, /* Report Size (8) */ 0x95, 0x03, /* Report Count (3) */ 0x81, 0x06, /* Input (Data, Variable, Relative) */ - 0xc0, /* End Collection */ - 0xc0, /* End Collection */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ }; static const uint8_t qemu_tablet_hid_report_descriptor[] = { - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x02, /* Usage (Mouse) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xa1, 0x00, /* Collection (Physical) */ - 0x05, 0x09, /* Usage Page (Button) */ - 0x19, 0x01, /* Usage Minimum (1) */ - 0x29, 0x03, /* Usage Maximum (3) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x95, 0x03, /* Report Count (3) */ - 0x75, 0x01, /* Report Size (1) */ - 0x81, 0x02, /* Input (Data, Variable, Absolute) */ - 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x05, /* Report Size (5) */ - 0x81, 0x01, /* Input (Constant) */ - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x30, /* Usage (X) */ - 0x09, 0x31, /* Usage (Y) */ - 0x15, 0x00, /* Logical Minimum (0) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x03, /* Usage Maximum (3) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input (Constant) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x15, 0x00, /* Logical Minimum (0) */ 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */ - 0x35, 0x00, /* Physical Minimum (0) */ + 0x35, 0x00, /* Physical Minimum (0) */ 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */ - 0x75, 0x10, /* Report Size (16) */ - 0x95, 0x02, /* Report Count (2) */ - 0x81, 0x02, /* Input (Data, Variable, Absolute) */ - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x38, /* Usage (Wheel) */ - 0x15, 0x81, /* Logical Minimum (-0x7f) */ - 0x25, 0x7f, /* Logical Maximum (0x7f) */ - 0x35, 0x00, /* Physical Minimum (same as logical) */ - 0x45, 0x00, /* Physical Maximum (same as logical) */ - 0x75, 0x08, /* Report Size (8) */ - 0x95, 0x01, /* Report Count (1) */ - 0x81, 0x06, /* Input (Data, Variable, Relative) */ - 0xc0, /* End Collection */ - 0xc0, /* End Collection */ + 0x75, 0x10, /* Report Size (16) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x15, 0x81, /* Logical Minimum (-0x7f) */ + 0x25, 0x7f, /* Logical Maximum (0x7f) */ + 0x35, 0x00, /* Physical Minimum (same as logical) */ + 0x45, 0x00, /* Physical Maximum (same as logical) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ }; static const uint8_t qemu_keyboard_hid_report_descriptor[] = { @@ -433,12 +399,12 @@ namespace usb_hid 0x19, 0x00, /* Usage Minimum (0) */ 0x29, 0xff, /* Usage Maximum (255) */ 0x81, 0x00, /* Input (Data, Array) */ - 0xc0, /* End Collection */ + 0xc0, /* End Collection */ }; static const uint8_t beatmania_dev_desc[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ WBVAL(0x110), /* u16 bcdUSB; v1.10 */ 0x00, /* u8 bDeviceClass; */ @@ -452,21 +418,21 @@ namespace usb_hid WBVAL(0x0002), WBVAL(0x0020), /* u16 bcdDevice */ - 1, /* u8 iManufacturer; */ - 2, /* u8 iProduct; */ - 0, /* u8 iSerialNumber; */ + 1, /* u8 iManufacturer; */ + 2, /* u8 iProduct; */ + 0, /* u8 iSerialNumber; */ 0x01 /* u8 bNumConfigurations; */ }; static const uint8_t beatmania_config_desc[] = { - 0x09, // bLength - 0x02, // bDescriptorType (Configuration) + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) 0x22, 0x00, // wTotalLength 34 - 0x01, // bNumInterfaces 1 - 0x01, // bConfigurationValue - 0x02, // iConfiguration (String Index) - 0xA0, // bmAttributes Remote Wakeup - 0x14, // bMaxPower 40mA + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x02, // iConfiguration (String Index) + 0xA0, // bmAttributes Remote Wakeup + 0x14, // bMaxPower 40mA 0x09, // bLength 0x04, // bDescriptorType (Interface) @@ -478,82 +444,232 @@ namespace usb_hid 0x01, // bInterfaceProtocol 0x00, // iInterface (String Index) - 0x09, // bLength - 0x21, // bDescriptorType (HID) + 0x09, // bLength + 0x21, // bDescriptorType (HID) 0x10, 0x01, // bcdHID 1.10 - 0x0F, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) + 0x0F, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) 0x44, 0x00, // wDescriptorLength[0] 68 - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x81, // bEndpointAddress (IN/D2H) - 0x03, // bmAttributes (Interrupt) + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) 0x08, 0x00, // wMaxPacketSize 8 - 0x0A, // bInterval 10 (unit depends on device speed) + 0x0A, // bInterval 10 (unit depends on device speed) // 34 bytes }; static const uint8_t beatmania_dadada_hid_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x06, // Usage (Keyboard) - 0xA1, 0x01, // Collection (Application) - 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0xE0, // Usage Minimum (0xE0) - 0x29, 0xE7, // Usage Maximum (0xE7) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x08, // Report Count (8) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0x00, // Usage Minimum (0x00) - 0x29, 0xFF, // Usage Maximum (0xFF) - 0x15, 0x00, // Logical Minimum (0) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection (Application) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0xE0, // Usage Minimum (0xE0) + 0x29, 0xE7, // Usage Maximum (0xE7) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0x00, // Usage Minimum (0x00) + 0x29, 0xFF, // Usage Maximum (0xFF) + 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x75, 0x08, // Report Size (8) - 0x95, 0x06, // Report Count (6) - 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x08, // Usage Page (LEDs) - 0x19, 0x01, // Usage Minimum (Num Lock) - 0x29, 0x05, // Usage Maximum (Kana) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x05, // Report Count (5) - 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x75, 0x03, // Report Size (3) - 0x95, 0x01, // Report Count (1) - 0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection + 0x75, 0x08, // Report Size (8) + 0x95, 0x06, // Report Count (6) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x08, // Usage Page (LEDs) + 0x19, 0x01, // Usage Minimum (Num Lock) + 0x29, 0x05, // Usage Maximum (Kana) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x05, // Report Count (5) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x75, 0x03, // Report Size (3) + 0x95, 0x01, // Report Count (1) + 0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection // 68 bytes }; + static constexpr const std::pair s_qkeycode_names[] = { + {Q_KEY_CODE_0, "0"}, + {Q_KEY_CODE_1, "1"}, + {Q_KEY_CODE_2, "2"}, + {Q_KEY_CODE_3, "3"}, + {Q_KEY_CODE_4, "4"}, + {Q_KEY_CODE_5, "5"}, + {Q_KEY_CODE_6, "6"}, + {Q_KEY_CODE_7, "7"}, + {Q_KEY_CODE_8, "8"}, + {Q_KEY_CODE_9, "9"}, + {Q_KEY_CODE_A, "A"}, + {Q_KEY_CODE_AC_BACK, "ACBack"}, + {Q_KEY_CODE_AC_BOOKMARKS, "ACBookmarks"}, + {Q_KEY_CODE_AC_FORWARD, "ACForward"}, + {Q_KEY_CODE_AC_HOME, "ACHome"}, + {Q_KEY_CODE_AC_REFRESH, "ACRefresh"}, + {Q_KEY_CODE_AGAIN, "Again"}, + {Q_KEY_CODE_ALT, "Alt"}, + {Q_KEY_CODE_ALT_R, "Alt_r"}, + {Q_KEY_CODE_APOSTROPHE, "Apostrophe"}, + {Q_KEY_CODE_ASTERISK, "Asterisk"}, + {Q_KEY_CODE_AUDIOMUTE, "AudioMute"}, + {Q_KEY_CODE_AUDIONEXT, "AudioNext"}, + {Q_KEY_CODE_AUDIOPLAY, "AudioPlay"}, + {Q_KEY_CODE_AUDIOPREV, "AudioPrev"}, + {Q_KEY_CODE_AUDIOSTOP, "AudioStop"}, + {Q_KEY_CODE_B, "B"}, + {Q_KEY_CODE_BACKSLASH, "Backslash"}, + {Q_KEY_CODE_BACKSPACE, "Backspace"}, + {Q_KEY_CODE_BRACKET_LEFT, "BracketLeft"}, + {Q_KEY_CODE_BRACKET_RIGHT, "BracketRight"}, + {Q_KEY_CODE_C, "C"}, + {Q_KEY_CODE_CALCULATOR, "Calculator"}, + {Q_KEY_CODE_CAPS_LOCK, "Caps_lock"}, + {Q_KEY_CODE_COMMA, "Comma"}, + {Q_KEY_CODE_COMPOSE, "Compose"}, + {Q_KEY_CODE_COMPUTER, "Computer"}, + {Q_KEY_CODE_COPY, "Copy"}, + {Q_KEY_CODE_CTRL, "Ctrl"}, + {Q_KEY_CODE_CTRL_R, "Ctrl_r"}, + {Q_KEY_CODE_CUT, "Cut"}, + {Q_KEY_CODE_D, "D"}, + {Q_KEY_CODE_DELETE, "Delete"}, + {Q_KEY_CODE_DOT, "Dot"}, + {Q_KEY_CODE_DOWN, "Down"}, + {Q_KEY_CODE_E, "E"}, + {Q_KEY_CODE_END, "End"}, + {Q_KEY_CODE_EQUAL, "Equal"}, + {Q_KEY_CODE_ESC, "Esc"}, + {Q_KEY_CODE_F, "F"}, + {Q_KEY_CODE_F1, "F1"}, + {Q_KEY_CODE_F10, "F10"}, + {Q_KEY_CODE_F11, "F11"}, + {Q_KEY_CODE_F12, "F12"}, + {Q_KEY_CODE_F2, "F2"}, + {Q_KEY_CODE_F3, "F3"}, + {Q_KEY_CODE_F4, "F4"}, + {Q_KEY_CODE_F5, "F5"}, + {Q_KEY_CODE_F6, "F6"}, + {Q_KEY_CODE_F7, "F7"}, + {Q_KEY_CODE_F8, "F8"}, + {Q_KEY_CODE_F9, "F9"}, + {Q_KEY_CODE_FIND, "Find"}, + {Q_KEY_CODE_FRONT, "Front"}, + {Q_KEY_CODE_G, "G"}, + {Q_KEY_CODE_GRAVE_ACCENT, "Agrave"}, + {Q_KEY_CODE_H, "H"}, + {Q_KEY_CODE_HELP, "Help"}, + {Q_KEY_CODE_HENKAN, "Henkan"}, + {Q_KEY_CODE_HIRAGANA, "Hiragana"}, + {Q_KEY_CODE_HOME, "Home"}, + {Q_KEY_CODE_I, "I"}, + {Q_KEY_CODE_INSERT, "Insert"}, + {Q_KEY_CODE_J, "J"}, + {Q_KEY_CODE_K, "K"}, + {Q_KEY_CODE_KATAKANAHIRAGANA, "KatakanaHiragana"}, + {Q_KEY_CODE_KP_0, "Numpad0"}, + {Q_KEY_CODE_KP_1, "Numpad1"}, + {Q_KEY_CODE_KP_2, "Numpad2"}, + {Q_KEY_CODE_KP_3, "Numpad3"}, + {Q_KEY_CODE_KP_4, "Numpad4"}, + {Q_KEY_CODE_KP_5, "Numpad5"}, + {Q_KEY_CODE_KP_6, "Numpad6"}, + {Q_KEY_CODE_KP_7, "Numpad7"}, + {Q_KEY_CODE_KP_8, "Numpad8"}, + {Q_KEY_CODE_KP_9, "Numpad9"}, + {Q_KEY_CODE_KP_ADD, "NumpadPlus"}, + {Q_KEY_CODE_KP_COMMA, "NumpadComma"}, + {Q_KEY_CODE_KP_DECIMAL, "NumpadPeriod"}, + {Q_KEY_CODE_KP_DIVIDE, "NumpadSlash"}, + {Q_KEY_CODE_KP_ENTER, "NumpadReturn"}, + {Q_KEY_CODE_KP_EQUALS, "NumpadEqual"}, + {Q_KEY_CODE_KP_MULTIPLY, "NumpadAsterisk"}, + {Q_KEY_CODE_KP_SUBTRACT, "NumpadMinus"}, + {Q_KEY_CODE_L, "L"}, + {Q_KEY_CODE_LEFT, "Left"}, + {Q_KEY_CODE_LESS, "Less"}, + {Q_KEY_CODE_LF, "Lf"}, + {Q_KEY_CODE_M, "M"}, + {Q_KEY_CODE_MAIL, "Mail"}, + {Q_KEY_CODE_MEDIASELECT, "MediaSelect"}, + {Q_KEY_CODE_MENU, "Menu"}, + {Q_KEY_CODE_META_L, "Meta"}, + {Q_KEY_CODE_META_R, "Meta"}, + {Q_KEY_CODE_MINUS, "Minus"}, + {Q_KEY_CODE_MUHENKAN, "Muhenkan"}, + {Q_KEY_CODE_N, "N"}, + {Q_KEY_CODE_NUM_LOCK, "Num_lock"}, + {Q_KEY_CODE_O, "O"}, + {Q_KEY_CODE_OPEN, "Open"}, + {Q_KEY_CODE_P, "P"}, + {Q_KEY_CODE_PASTE, "Paste"}, + {Q_KEY_CODE_PAUSE, "Pause"}, + {Q_KEY_CODE_PGDN, "PageDown"}, + {Q_KEY_CODE_PGUP, "PageUp"}, + {Q_KEY_CODE_POWER, "Power"}, + {Q_KEY_CODE_PRINT, "Print"}, + {Q_KEY_CODE_PROPS, "Props"}, + {Q_KEY_CODE_Q, "Q"}, + {Q_KEY_CODE_R, "R"}, + {Q_KEY_CODE_RET, "Return"}, + {Q_KEY_CODE_RIGHT, "Right"}, + {Q_KEY_CODE_RO, "Ro"}, + {Q_KEY_CODE_S, "S"}, + {Q_KEY_CODE_SCROLL_LOCK, "Scroll_lock"}, + {Q_KEY_CODE_SEMICOLON, "Semicolon"}, + {Q_KEY_CODE_SHIFT, "Shift"}, + {Q_KEY_CODE_SHIFT_R, "Shift_r"}, + {Q_KEY_CODE_SLASH, "Slash"}, + {Q_KEY_CODE_SLEEP, "Sleep"}, + {Q_KEY_CODE_SPC, "Spc"}, + {Q_KEY_CODE_STOP, "Stop"}, + {Q_KEY_CODE_SYSRQ, "Sysrq"}, + {Q_KEY_CODE_T, "T"}, + {Q_KEY_CODE_TAB, "Tab"}, + {Q_KEY_CODE_U, "U"}, + {Q_KEY_CODE_UNDO, "Undo"}, + {Q_KEY_CODE_UP, "Up"}, + {Q_KEY_CODE_V, "V"}, + {Q_KEY_CODE_VOLUMEDOWN, "VolumeDown"}, + {Q_KEY_CODE_VOLUMEUP, "VolumeUp"}, + {Q_KEY_CODE_W, "W"}, + {Q_KEY_CODE_WAKE, "Wake"}, + {Q_KEY_CODE_X, "X"}, + {Q_KEY_CODE_Y, "Y"}, + {Q_KEY_CODE_YEN, "Yen"}, + {Q_KEY_CODE_Z, "Z"}, + }; + static void usb_hid_changed(HIDState* hs) { - UsbHIDState* us = CONTAINER_OF(hs, UsbHIDState, f.hid); + UsbHIDState* us = USB_CONTAINER_OF(hs, UsbHIDState, hid); usb_wakeup(us->intr, 0); } static void usb_hid_handle_reset(USBDevice* dev) { - UsbHIDState* us = reinterpret_cast(dev); + UsbHIDState* us = USB_CONTAINER_OF(dev, UsbHIDState, dev); - hid_reset(&us->f.hid); + hid_reset(&us->hid); } static void usb_hid_handle_control(USBDevice* dev, USBPacket* p, - int request, int value, int index, int length, uint8_t* data) + int request, int value, int index, int length, uint8_t* data) { - UsbHIDState* us = reinterpret_cast(dev); - HIDState* hs = &us->f.hid; + UsbHIDState* us = USB_CONTAINER_OF(dev, UsbHIDState, dev); + HIDState* hs = &us->hid; int ret; DevCon.WriteLn("usb-hid: req %04X val: %04X idx: %04X len: %d\n", request, value, index, length); @@ -573,13 +689,13 @@ namespace usb_hid if (hs->kind == HID_MOUSE) { memcpy(data, qemu_mouse_hid_report_descriptor, - sizeof(qemu_mouse_hid_report_descriptor)); + sizeof(qemu_mouse_hid_report_descriptor)); p->actual_length = sizeof(qemu_mouse_hid_report_descriptor); } else if (hs->kind == HID_TABLET) { memcpy(data, qemu_tablet_hid_report_descriptor, - sizeof(qemu_tablet_hid_report_descriptor)); + sizeof(qemu_tablet_hid_report_descriptor)); p->actual_length = sizeof(qemu_tablet_hid_report_descriptor); } else if (hs->kind == HID_KEYBOARD) @@ -657,8 +773,8 @@ namespace usb_hid static void usb_hid_handle_data(USBDevice* dev, USBPacket* p) { - UsbHIDState* us = reinterpret_cast(dev); - HIDState* hs = &us->f.hid; + UsbHIDState* us = USB_CONTAINER_OF(dev, UsbHIDState, dev); + HIDState* hs = &us->hid; std::vector buf(p->iov.size); size_t len = 0; @@ -702,54 +818,79 @@ namespace usb_hid static void usb_hid_unrealize(USBDevice* dev) { - UsbHIDState* us = reinterpret_cast(dev); - - hid_free(&us->f.hid); - + UsbHIDState* us = USB_CONTAINER_OF(dev, UsbHIDState, dev); + hid_free(&us->hid); delete us; } - int usb_hid_open(USBDevice* dev) + UsbHIDState::UsbHIDState(u32 port_) + : port(port_) { - UsbHIDState* s = (UsbHIDState*)dev; - if (s) - return s->usbhid->Open(); - return 0; } - void usb_hid_close(USBDevice* dev) + // NOTE: This is really cruddy, reusing qemu's stuff here, when we could just do + // it ourselves. But this code isn't used often enough to make it worthwhile. + + void UsbHIDState::QueueMouseButtonState(InputButton button, bool pressed) { - UsbHIDState* s = (UsbHIDState*)dev; - if (s) - s->usbhid->Close(); + InputEvent evt; + evt.type = INPUT_EVENT_KIND_BTN; + evt.u.btn.button = button; + evt.u.btn.down = pressed; + hid.ptr.eh_entry(&hid, &evt); + hid.ptr.eh_sync(&hid); } - USBDevice* HIDKbdDevice::CreateDevice(int port) + void UsbHIDState::QueueMouseAxisState(InputPointerAxis axis, float delta) { - UsbHIDState* s; - - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - UsbHIDProxyBase* proxy = RegisterUsbHID::instance().Proxy(varApi); - if (!proxy) + if (axis < InputPointerAxis::WheelX) { - Console.WriteLn("Invalid HID API: %s \n", varApi.c_str()); - return nullptr; + // x/y + InputEvent evt; + evt.type = INPUT_EVENT_KIND_REL; + evt.u.rel.axis = static_cast(axis); + evt.u.rel.value = static_cast(delta); + hid.ptr.eh_entry(&hid, &evt); + hid.ptr.eh_sync(&hid); } + else if (axis == InputPointerAxis::WheelY) + { + InputEvent evt; + evt.type = INPUT_EVENT_KIND_BTN; + evt.u.btn.button = (delta > 0.0f) ? INPUT_BUTTON_WHEEL_DOWN : INPUT_BUTTON_WHEEL_UP; + evt.u.btn.down = true; + hid.ptr.eh_entry(&hid, &evt); + hid.ptr.eh_sync(&hid); + } + } - UsbHID* usbhid = proxy->CreateObject(port, TypeName()); + void UsbHIDState::SetKeycodeMapping() + { + for (const auto& [keycode, name] : s_qkeycode_names) + { + std::optional hkeycode(InputManager::ConvertHostKeyboardStringToCode(name)); + if (!hkeycode.has_value()) + { + DevCon.WriteLn("(UsbHIDState): Missing host mapping for QKey '%s'", name); + continue; + } - if (!usbhid) - return nullptr; + keycode_mapping.emplace(hkeycode.value(), keycode); + } + } - s = new UsbHIDState(); + void UsbHIDState::QueueKeyboardState(KeyValue keycode, bool pressed) + { + InputEvent evt; + evt.type = INPUT_EVENT_KIND_KEY; + evt.u.key.key = keycode; + evt.u.key.down = pressed; + hid.kbd.eh_entry(&hid, &evt); + } + USBDevice* HIDKbdDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + UsbHIDState* s = new UsbHIDState(port); s->desc.full = &s->desc_dev; s->desc.str = desc_strings; @@ -758,96 +899,87 @@ namespace usb_hid if (usb_desc_parse_config(kbd_config_desc, sizeof(kbd_config_desc), s->desc_dev) < 0) goto fail; - s->usbhid = usbhid; s->dev.speed = USB_SPEED_FULL; s->dev.klass.handle_attach = usb_desc_attach; s->dev.klass.handle_reset = usb_hid_handle_reset; s->dev.klass.handle_control = usb_hid_handle_control; s->dev.klass.handle_data = usb_hid_handle_data; s->dev.klass.unrealize = usb_hid_unrealize; - s->dev.klass.open = usb_hid_open; - s->dev.klass.close = usb_hid_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = s->desc.str[2]; - s->port = port; usb_desc_init(&s->dev); usb_ep_init(&s->dev); s->intr = usb_ep_get(&s->dev, USB_TOKEN_IN, 1); - hid_init(&s->f.hid, HID_KEYBOARD, usb_hid_changed); - s->usbhid->SetHIDState(&s->f.hid); - s->usbhid->SetHIDType(HIDTYPE_KBD); + hid_init(&s->hid, HID_KEYBOARD, usb_hid_changed); - usb_hid_handle_reset((USBDevice*)s); + usb_hid_handle_reset(&s->dev); - return (USBDevice*)s; + s->SetKeycodeMapping(); + + return &s->dev; fail: - usb_hid_unrealize((USBDevice*)s); + usb_hid_unrealize(&s->dev); return nullptr; } - int HIDKbdDevice::Configure(int port, const std::string& api, void* data) + void HIDKbdDevice::SetBindingValue(USBDevice* dev, u32 bind, float value) const { - auto proxy = RegisterUsbHID::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), HIDTYPE_KBD, data); - return RESULT_CANCELED; + UsbHIDState* s = USB_CONTAINER_OF(dev, UsbHIDState, dev); + + const auto it = s->keycode_mapping.find(bind); + if (it == s->keycode_mapping.end()) + return; + + KeyValue kv; + kv.type = KEY_VALUE_KIND_QCODE; + kv.u.qcode = it->second; + s->QueueKeyboardState(kv, (value >= 0.5f)); } - int HIDKbdDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* HIDKbdDevice::Name() const { - auto s = reinterpret_cast(dev); - auto freezed = reinterpret_cast(data); - - if (!s) - return 0; - switch (mode) - { - case FreezeAction::Load: - if (!s) - return -1; - s->f = *freezed; - hid_init(&s->f.hid, HID_KEYBOARD, usb_hid_changed); - - return sizeof(UsbHIDState::freeze); - case FreezeAction::Save: - if (!s) - return -1; - *freezed = s->f; - return sizeof(UsbHIDState::freeze); - case FreezeAction::Size: - return sizeof(UsbHIDState::freeze); - default: - break; - } - return 0; + return "HID Keyboard"; } - USBDevice* HIDMouseDevice::CreateDevice(int port) + const char* HIDKbdDevice::TypeName() const { - UsbHIDState* s; + return "hidkbd"; + } - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - UsbHIDProxyBase* proxy = RegisterUsbHID::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("Invalid HID API: %s\n", varApi.c_str()); - return nullptr; - } + gsl::span HIDKbdDevice::Bindings(u32 subtype) const + { + static constexpr const InputBindingInfo info[] = { + {"Keyboard", "Keyboard", InputBindingInfo::Type::Keyboard, 0, GenericInputBinding::Unknown}, + }; + return info; + } - UsbHID* usbhid = proxy->CreateObject(port, TypeName()); + bool HIDKbdDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + UsbHIDState* s = USB_CONTAINER_OF(dev, UsbHIDState, dev); - if (!usbhid) - return nullptr; + if (!sw.DoMarker("HIDKbdDevice")) + return false; - s = new UsbHIDState(); + sw.DoPODArray(s->hid.kbd.keycodes, std::size(s->hid.kbd.keycodes)); + sw.Do(&s->hid.kbd.modifiers); + sw.Do(&s->hid.kbd.leds); + sw.DoPODArray(&s->hid.kbd.key, std::size(s->hid.kbd.key)); + sw.Do(&s->hid.kbd.keys); + + sw.Do(&s->hid.head); + sw.Do(&s->hid.n); + sw.Do(&s->hid.protocol); + sw.Do(&s->hid.idle); + sw.Do(&s->hid.idle_pending); + + return !sw.HasError(); + } + + USBDevice* HIDMouseDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + UsbHIDState* s = new UsbHIDState(port); s->desc.full = &s->desc_dev; s->desc.str = desc_strings; @@ -857,99 +989,105 @@ namespace usb_hid if (usb_desc_parse_config(qemu_mouse_config_descriptor, sizeof(qemu_mouse_config_descriptor), s->desc_dev) < 0) goto fail; - s->usbhid = usbhid; s->dev.speed = USB_SPEED_FULL; s->dev.klass.handle_attach = usb_desc_attach; s->dev.klass.handle_reset = usb_hid_handle_reset; s->dev.klass.handle_control = usb_hid_handle_control; s->dev.klass.handle_data = usb_hid_handle_data; s->dev.klass.unrealize = usb_hid_unrealize; - s->dev.klass.open = usb_hid_open; - s->dev.klass.close = usb_hid_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = s->desc.str[STR_CONFIG_MOUSE]; - s->port = port; usb_desc_init(&s->dev); usb_ep_init(&s->dev); s->intr = usb_ep_get(&s->dev, USB_TOKEN_IN, 1); - hid_init(&s->f.hid, HID_MOUSE, usb_hid_changed); - s->usbhid->SetHIDState(&s->f.hid); - s->usbhid->SetHIDType(HIDTYPE_MOUSE); + hid_init(&s->hid, HID_MOUSE, usb_hid_changed); - usb_hid_handle_reset((USBDevice*)s); + usb_hid_handle_reset(&s->dev); - return (USBDevice*)s; + return &s->dev; fail: - usb_hid_unrealize((USBDevice*)s); + usb_hid_unrealize(&s->dev); return nullptr; } - int HIDMouseDevice::Configure(int port, const std::string& api, void* data) + const char* HIDMouseDevice::Name() const { - auto proxy = RegisterUsbHID::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), HIDTYPE_MOUSE, data); - return RESULT_CANCELED; + return "HID Mouse"; } - int HIDMouseDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* HIDMouseDevice::TypeName() const { - auto s = reinterpret_cast(dev); - auto freezed = reinterpret_cast(data); + return "hidmouse"; + } - if (!s) - return 0; - switch (mode) + bool HIDMouseDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + UsbHIDState* s = USB_CONTAINER_OF(dev, UsbHIDState, dev); + + if (!sw.DoMarker("HIDMouseDevice")) + return false; + + sw.DoPODArray(s->hid.ptr.queue, std::size(s->hid.ptr.queue)); + sw.Do(&s->hid.ptr.mouse_grabbed); + + sw.Do(&s->hid.head); + sw.Do(&s->hid.n); + sw.Do(&s->hid.protocol); + sw.Do(&s->hid.idle); + sw.Do(&s->hid.idle_pending); + + return !sw.HasError(); + } + + gsl::span HIDMouseDevice::Bindings(u32 subtype) const + { + static constexpr const InputBindingInfo info[] = { + {"Pointer", "Pointer", InputBindingInfo::Type::Pointer, INPUT_BUTTON__MAX, GenericInputBinding::Unknown}, + {"LeftButton", "Left Button", InputBindingInfo::Type::Button, INPUT_BUTTON_LEFT, GenericInputBinding::Unknown}, + {"RightButton", "Right Button", InputBindingInfo::Type::Button, INPUT_BUTTON_RIGHT, GenericInputBinding::Unknown}, + {"MiddleButton", "Middle Button", InputBindingInfo::Type::Button, INPUT_BUTTON_MIDDLE, GenericInputBinding::Unknown}, + }; + return info; + } + + float HIDMouseDevice::GetBindingValue(const USBDevice* dev, u32 bind) const + { + const UsbHIDState* s = USB_CONTAINER_OF(dev, const UsbHIDState, dev); + + if (bind >= INPUT_BUTTON__MAX) { - case FreezeAction::Load: - if (!s) - return -1; - s->f = *freezed; - hid_init(&s->f.hid, HID_MOUSE, usb_hid_changed); - - return sizeof(UsbHIDState::freeze); - case FreezeAction::Save: - if (!s) - return -1; - *freezed = s->f; - return sizeof(UsbHIDState::freeze); - case FreezeAction::Size: - return sizeof(UsbHIDState::freeze); - default: - break; + // axis, don't bother returning, we don't have an absolute value here anyway + return 0.0f; } - return 0; + + const int index = (s->hid.n ? s->hid.head : s->hid.head - 1); + const HIDPointerEvent* e = &s->hid.ptr.queue[index & QUEUE_MASK]; + + static const int bmap[INPUT_BUTTON__MAX] = { + /*[INPUT_BUTTON_LEFT] =*/0x01, + /*[INPUT_BUTTON_MIDDLE] =*/0x04, + /*[INPUT_BUTTON_RIGHT] =*/0x02, + 0, 0, 0, 0}; + + return ((e->buttons_state & bmap[bind]) != 0) ? 1.0f : 0.0f; + } + + void HIDMouseDevice::SetBindingValue(USBDevice* dev, u32 bind, float value) const + { + UsbHIDState* s = USB_CONTAINER_OF(dev, UsbHIDState, dev); + + if (bind < INPUT_BUTTON__MAX) + s->QueueMouseButtonState(static_cast(bind), (value >= 0.5f)); + else + s->QueueMouseAxisState(static_cast(bind - INPUT_BUTTON__MAX), value); } // ---- BeatMania Da Da Da!! ---- - USBDevice* BeatManiaDevice::CreateDevice(int port) + USBDevice* BeatManiaDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { - DevCon.WriteLn("%s\n", __func__); - UsbHIDState* s; - - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - UsbHIDProxyBase* proxy = RegisterUsbHID::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("Invalid HID API: %s\n", varApi.c_str()); - return nullptr; - } - - UsbHID* usbhid = proxy->CreateObject(port, TypeName()); - - if (!usbhid) - return nullptr; - - s = new UsbHIDState(); + UsbHIDState* s = new UsbHIDState(port); s->desc.full = &s->desc_dev; s->desc.str = beatmania_dadada_desc_strings; @@ -959,46 +1097,44 @@ namespace usb_hid if (usb_desc_parse_config(beatmania_config_desc, sizeof(beatmania_config_desc), s->desc_dev) < 0) goto fail; - s->usbhid = usbhid; s->dev.speed = USB_SPEED_FULL; s->dev.klass.handle_attach = usb_desc_attach; s->dev.klass.handle_reset = usb_hid_handle_reset; s->dev.klass.handle_control = usb_hid_handle_control; s->dev.klass.handle_data = usb_hid_handle_data; s->dev.klass.unrealize = usb_hid_unrealize; - s->dev.klass.open = usb_hid_open; - s->dev.klass.close = usb_hid_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = s->desc.str[2]; - s->port = port; usb_desc_init(&s->dev); usb_ep_init(&s->dev); s->intr = usb_ep_get(&s->dev, USB_TOKEN_IN, 1); - hid_init(&s->f.hid, HID_KEYBOARD, usb_hid_changed); - s->f.hid.sub_kind = HID_SUBKIND_BEATMANIA; - s->usbhid->SetHIDState(&s->f.hid); - s->usbhid->SetHIDType(HIDTYPE_KBD); + hid_init(&s->hid, HID_KEYBOARD, usb_hid_changed); + s->hid.sub_kind = HID_SUBKIND_BEATMANIA; - usb_hid_handle_reset((USBDevice*)s); + usb_hid_handle_reset(&s->dev); - return (USBDevice*)s; + s->SetKeycodeMapping(); + + return &s->dev; fail: - usb_hid_unrealize((USBDevice*)s); + usb_hid_unrealize(&s->dev); return nullptr; } - int BeatManiaDevice::Configure(int port, const std::string& api, void* data) + const char* BeatManiaDevice::Name() const { - auto proxy = RegisterUsbHID::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), HIDTYPE_KBD, data); - return RESULT_CANCELED; + return "BeatMania Da Da Da!! Keyboard"; } - int BeatManiaDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* BeatManiaDevice::TypeName() const { - return HIDKbdDevice::Freeze(mode, dev, data); + return "beatmania"; + } + + bool BeatManiaDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + return HIDKbdDevice::Freeze(dev, sw); } } // namespace usb_hid diff --git a/pcsx2/USB/usb-hid/usb-hid.h b/pcsx2/USB/usb-hid/usb-hid.h index 9b905c69b2..627056fe00 100644 --- a/pcsx2/USB/usb-hid/usb-hid.h +++ b/pcsx2/USB/usb-hid/usb-hid.h @@ -15,114 +15,42 @@ #pragma once #include "SaveState.h" -#include "USB/configuration.h" #include "USB/qemu-usb/hid.h" #include #include namespace usb_hid { - - enum HIDType - { - HIDTYPE_KBD, - HIDTYPE_MOUSE, - }; - - class UsbHID + class HIDKbdDevice : public DeviceProxy { public: - UsbHID(int port, const char* dev_type) - : mPort(port) - , mDevType(dev_type) - { - } - virtual ~UsbHID() {} - virtual int Open() = 0; - virtual int Close() = 0; - // virtual int TokenIn(uint8_t *buf, int len) = 0; - virtual int TokenOut(const uint8_t* data, int len) = 0; - virtual int Reset() = 0; - - virtual int Port() { return mPort; } - virtual void Port(int port) { mPort = port; } - virtual void SetHIDState(HIDState* hs) { mHIDState = hs; } - virtual void SetHIDType(HIDType t) { mHIDType = t; } - - protected: - int mPort; - HIDState* mHIDState; - HIDType mHIDType; - const char* mDevType; + const char* Name() const override; + const char* TypeName() const override; + gsl::span Bindings(u32 subtype) const override; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + void SetBindingValue(USBDevice* dev, u32 bind, float value) const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; }; - class HIDKbdDevice + class HIDMouseDevice final : public DeviceProxy { public: - virtual ~HIDKbdDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("HID Keyboard"); - } - static const char* TypeName() - { - return "hidkbd"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + const char* Name() const override; + const char* TypeName() const override; + gsl::span Bindings(u32 subtype) const override; + float GetBindingValue(const USBDevice* dev, u32 bind) const override; + void SetBindingValue(USBDevice* dev, u32 bind, float value) const override; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; }; - class HIDMouseDevice + class BeatManiaDevice final : public HIDKbdDevice { public: - virtual ~HIDMouseDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("HID Mouse"); - } - static const char* TypeName() - { - return "hidmouse"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } - }; - - class BeatManiaDevice - { - public: - virtual ~BeatManiaDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("BeatMania Da Da Da!! Keyboard"); - } - static const char* TypeName() - { - return "beatmania"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + const char* Name() const override; + const char* TypeName() const override; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; }; } // namespace usb_hid diff --git a/pcsx2/USB/usb-lightgun/guncon2.cpp b/pcsx2/USB/usb-lightgun/guncon2.cpp new file mode 100644 index 0000000000..a4c269f75c --- /dev/null +++ b/pcsx2/USB/usb-lightgun/guncon2.cpp @@ -0,0 +1,557 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "USB/deviceproxy.h" +#include "USB/qemu-usb/desc.h" +#include "USB/usb-lightgun/guncon2.h" +#include "USB/qemu-usb/USBinternal.h" +#include "USB/USB.h" +#include "GS/GS.h" +#include "HostDisplay.h" +#include "StateWrapper.h" +#include "VMManager.h" + +#include "Frontend/InputManager.h" + +#include + +namespace usb_lightgun +{ + enum : u32 + { + GUNCON2_FLAG_PROGRESSIVE = 0x0100, + + GUNCON2_CALIBRATION_DELAY = 9 + }; + + enum : u32 + { + BID_C = 1, + BID_B = 2, + BID_A = 3, + BID_DPAD_UP = 4, + BID_DPAD_RIGHT = 5, + BID_DPAD_DOWN = 6, + BID_DPAD_LEFT = 7, + BID_TRIGGER = 13, + BID_SELECT = 14, + BID_START = 15, + BID_SHOOT_OFFSCREEN = 16, + BID_RECALIBRATE = 17, + }; + + // Right pain in the arse. Different games seem to have different scales.. + // Not worth putting these in the gamedb for such few games. + // Values are from the old nuvee plugin. + struct GameConfig + { + const char* serial; + float scale_x, scale_y; + u32 center_x, center_y; + u32 screen_width, screen_height; + }; + + static constexpr const GameConfig s_game_config[] = { + {"SLUS-20485", 90.25, 92.5, 390, 132, 640, 240}, // Dino Stalker (U) + {"SLUS-20389", 89.25, 93.5, 422, 141, 640, 240}, // Endgame (U) + {"SLES-52620", 90.5, 114.75, 390, 146, 640, 256}, // Guncom 2 (E) + {"SLES-51289", 84.5, 89.0, 456, 164, 640, 256}, // Gunfighter 2 - Jesse James (E) + {"SLPS-25165", 90.25, 98.0, 390, 138, 640, 240}, // Gunvari Collection (J) (480i) + // {"SLPS-25165", 86.75, 96.0, 454, 164, 640, 256}, // Gunvari Collection (J) (480p) + {"SCES-50889", 90.25, 94.5, 390, 169, 640, 256}, // Ninja Assault (E) + {"SLUS-20492", 90.25, 92.5, 390, 132, 640, 240}, // Ninja Assault (U) + {"SLES-50650", 84.75, 96.0, 454, 164, 640, 240}, // Resident Evil Survivor 2 (E) + {"SLES-51448", 90.25, 93.5, 420, 132, 640, 240}, // Resident Evil - Dead Aim (U) + {"SLUS-20619", 90.25, 91.75, 453, 154, 640, 256}, // Starsky & Hutch (U) + {"SLUS-20219", 90.25, 97.5, 390, 154, 640, 240}, // Time Crisis 2 (U) + {"SLUS-20645", 90.25, 97.5, 390, 154, 640, 240}, // Time Crisis 3 (U) + {"SLUS-20927", 90.25, 99.0, 390, 153, 640, 240}, // Time Crisis - Crisis Zone (U) (480i) + // {"SLUS-20927", 94.5, 104.75, 423, 407, 768, 768}, // Time Crisis - Crisis Zone (U) (480p) + {"SLUS-20221", 97.5, 104.75, 423, 407, 768, 768}, // Vampire Night (U) + {"SLES-51229", 88.75, 100.0, 454, 164, 640, 256}, // Virtua Cop - Elite Edition (E,J) (480i) + // {"SLES-51229", 85.75, 92.0, 456, 164, 640, 256}, // Virtua Cop - Elite Edition (E,J) (480p) + }; + + static constexpr s32 DEFAULT_SCREEN_WIDTH = 640; + static constexpr s32 DEFAULT_SCREEN_HEIGHT = 480; + static constexpr float DEFAULT_CENTER_X = 320.0f; + static constexpr float DEFAULT_CENTER_Y = 120.0f; + static constexpr float DEFAULT_SCALE_X = 100.0f; + static constexpr float DEFAULT_SCALE_Y = 100.0f; + +#pragma pack(push, 1) + union GunCon2Out + { + u8 bits[6]; + + struct + { + u16 buttons; + s16 pos_x; + s16 pos_y; + }; + }; + static_assert(sizeof(GunCon2Out) == 6); +#pragma pack(pop) + + struct GunCon2State + { + explicit GunCon2State(u32 port_); + + USBDevice dev{}; + USBDesc desc{}; + USBDescDevice desc_dev{}; + + u32 port = 0; + + ////////////////////////////////////////////////////////////////////////// + // Configuration + ////////////////////////////////////////////////////////////////////////// + bool custom_config = false; + u32 screen_width = 640; + u32 screen_height = 240; + float center_x = 320; + float center_y = 120; + float scale_x = 1.0f; + float scale_y = 1.0f; + + ////////////////////////////////////////////////////////////////////////// + // Host State (Not Saved) + ////////////////////////////////////////////////////////////////////////// + u32 button_state = 0; + + ////////////////////////////////////////////////////////////////////////// + // Device State (Saved) + ////////////////////////////////////////////////////////////////////////// + s16 param_x = 0; + s16 param_y = 0; + u16 param_mode = 0; + + u16 calibration_timer = 0; + s16 calibration_pos_x = 0; + s16 calibration_pos_y = 0; + + bool auto_config_done = false; + + void AutoConfigure(); + + std::tuple CalculatePosition(); + }; + + static const USBDescStrings desc_strings = { + "Namco GunCon2", + }; + + /* mostly the same values as the Bochs USB Keyboard device */ + static const uint8_t guncon2_dev_desc[] = { + /* bLength */ 0x12, + /* bDescriptorType */ 0x01, + /* bcdUSB */ WBVAL(0x0100), + /* bDeviceClass */ 0x00, + /* bDeviceSubClass */ 0x00, + /* bDeviceProtocol */ 0x00, + /* bMaxPacketSize0 */ 0x08, + /* idVendor */ WBVAL(0x0b9a), + /* idProduct */ WBVAL(0x016a), + /* bcdDevice */ WBVAL(0x0100), + /* iManufacturer */ 0x00, + /* iProduct */ 0x00, + /* iSerialNumber */ 0x00, + /* bNumConfigurations */ 0x01, + }; + + static const uint8_t guncon2_config_desc[] = { + 0x09, // Length + 0x02, // Type (Config) + 0x19, 0x00, // Total size + + 0x01, // # interfaces + 0x01, // Configuration # + 0x00, // index of string descriptor + 0x80, // Attributes (bus powered) + 0x19, // Max power in mA + + + // Interface + 0x09, // Length + 0x04, // Type (Interface) + + 0x00, // Interface # + 0x00, // Alternative # + 0x01, // # endpoints + + 0xff, // Class + 0x6a, // Subclass + 0x00, // Protocol + 0x00, // index of string descriptor + + + // Endpoint + 0x07, // Length + 0x05, // Type (Endpoint) + + 0x81, // Address + 0x03, // Attributes (interrupt transfers) + 0x08, 0x00, // Max packet size + + 0x08, // Polling interval (frame counts) + }; + + static void guncon2_handle_control( + USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) + { + GunCon2State* const us = USB_CONTAINER_OF(dev, GunCon2State, dev); + + // Apply configuration on the first control packet. + // The ELF should be well and truely loaded by then. + if (!us->auto_config_done && !us->custom_config) + { + us->AutoConfigure(); + us->auto_config_done = true; + } + + DevCon.WriteLn("guncon2: req %04X val: %04X idx: %04X len: %d\n", request, value, index, length); + if (usb_desc_handle_control(dev, p, request, value, index, length, data) >= 0) + return; + + if (request == (ClassInterfaceOutRequest | 0x09)) + { + us->param_x = static_cast(data[0]) | (static_cast(data[1]) << 8); + us->param_y = static_cast(data[2]) | (static_cast(data[3]) << 8); + us->param_mode = static_cast(data[4]) | (static_cast(data[5]) << 8); + DevCon.WriteLn("GunCon2 Set Param %04X %d %d", us->param_mode, us->param_x, us->param_y); + return; + } + + p->status = USB_RET_STALL; + } + + static void guncon2_handle_data(USBDevice* dev, USBPacket* p) + { + GunCon2State* const us = USB_CONTAINER_OF(dev, GunCon2State, dev); + + switch (p->pid) + { + case USB_TOKEN_IN: + { + if (p->ep->nr == 1) + { + const auto [pos_x, pos_y] = us->CalculatePosition(); + + // Time Crisis games do a "calibration" by displaying a black frame for a single frame, + // waiting for the gun to report (0, 0), and then computing an offset on the first non-zero + // value. So, after the trigger is pulled, we wait for a few frames, then send the (0, 0) + // report, then go back to normal values. To reduce error if the mouse is moving during + // these frames (unlikely), we store the fire position and keep returning that. + if (us->button_state & (1u << BID_RECALIBRATE) && us->calibration_timer == 0) + { + us->calibration_timer = GUNCON2_CALIBRATION_DELAY; + us->calibration_pos_x = pos_x; + us->calibration_pos_y = pos_y; + } + + // Buttons are active low. + GunCon2Out out; + out.buttons = static_cast(~us->button_state) | (us->param_mode & GUNCON2_FLAG_PROGRESSIVE); + out.pos_x = pos_x; + out.pos_y = pos_y; + + if (us->calibration_timer > 0) + { + // Force trigger down while calibrating. + out.buttons &= ~(1u << BID_TRIGGER); + out.pos_x = us->calibration_pos_x; + out.pos_y = us->calibration_pos_y; + us->calibration_timer--; + + if (us->calibration_timer == 0) + { + out.pos_x = 0; + out.pos_y = 0; + } + } + else if (us->button_state & (1u << BID_SHOOT_OFFSCREEN)) + { + // Offscreen shot - use 0,0. + out.buttons &= ~(1u << BID_TRIGGER); + out.pos_x = 0; + out.pos_y = 0; + } + + usb_packet_copy(p, &out, sizeof(out)); + break; + } + } + [[fallthrough]]; + + case USB_TOKEN_OUT: + default: + { + Console.Error("Unhandled GunCon2 request pid=%d ep=%u", p->pid, p->ep->nr); + p->status = USB_RET_STALL; + } + break; + } + } + + static void usb_hid_unrealize(USBDevice* dev) + { + GunCon2State* us = USB_CONTAINER_OF(dev, GunCon2State, dev); + delete us; + } + + GunCon2State::GunCon2State(u32 port_) + : port(port_) + { + } + + void GunCon2State::AutoConfigure() + { + const std::string serial(VMManager::GetGameSerial()); + for (const GameConfig& gc : s_game_config) + { + if (serial != gc.serial) + continue; + + Console.WriteLn(fmt::format("(GunCon2) Using automatic config for '{}'", serial)); + Console.WriteLn(fmt::format(" Scale: {}x{}", gc.scale_x / 100.0f, gc.scale_y / 100.0f)); + Console.WriteLn(fmt::format(" Center Position: {}x{}", gc.center_x, gc.center_y)); + Console.WriteLn(fmt::format(" Screen Size: {}x{}", gc.screen_width, gc.screen_height)); + + scale_x = gc.scale_x / 100.0f; + scale_y = gc.scale_y / 100.0f; + center_x = static_cast(gc.center_x); + center_y = static_cast(gc.center_y); + screen_width = gc.screen_width; + screen_height = gc.screen_height; + return; + } + + Console.Warning(fmt::format("(GunCon2) No automatic config found for '{}'.", serial)); + } + + std::tuple GunCon2State::CalculatePosition() + { + float pointer_x, pointer_y; + const std::pair abs_pos(InputManager::GetPointerAbsolutePosition(0)); + GSTranslateWindowToDisplayCoordinates(abs_pos.first, abs_pos.second, &pointer_x, &pointer_y); + + s16 pos_x, pos_y; + if (pointer_x < 0.0f || pointer_y < 0.0f || (button_state & BID_SHOOT_OFFSCREEN)) + { + // off-screen + pos_x = 0; + pos_y = 0; + } + else + { + // scale to internal coordinate system and center + float fx = (pointer_x * static_cast(screen_width)) - static_cast(screen_width / 2u); + float fy = (pointer_y * static_cast(screen_height)) - static_cast(screen_height / 2u); + + // apply curvature scale + fx *= scale_x; + fy *= scale_y; + + // and re-center based on game center + s32 x = static_cast(std::round(fx + center_x)); + s32 y = static_cast(std::round(fy + center_y)); + + // apply game-configured offset + if (param_mode & GUNCON2_FLAG_PROGRESSIVE) + { + x -= param_x / 2; + y -= param_y / 2; + } + else + { + x -= param_x; + y -= param_y; + } + + // 0,0 is reserved for offscreen, so ensure we don't send that + pos_x = static_cast(std::max(x, 1)); + pos_y = static_cast(std::max(y, 1)); + } + + return std::tie(pos_x, pos_y); + } + + const char* GunCon2Device::Name() const + { + return "GunCon 2"; + } + + const char* GunCon2Device::TypeName() const + { + return "guncon2"; + } + + USBDevice* GunCon2Device::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + GunCon2State* s = new GunCon2State(port); + s->desc.full = &s->desc_dev; + s->desc.str = desc_strings; + + if (usb_desc_parse_dev(guncon2_dev_desc, sizeof(guncon2_dev_desc), s->desc, s->desc_dev) < 0) + goto fail; + if (usb_desc_parse_config(guncon2_config_desc, sizeof(guncon2_config_desc), s->desc_dev) < 0) + goto fail; + + s->dev.speed = USB_SPEED_FULL; + s->dev.klass.handle_attach = usb_desc_attach; + s->dev.klass.handle_control = guncon2_handle_control; + s->dev.klass.handle_data = guncon2_handle_data; + s->dev.klass.unrealize = usb_hid_unrealize; + s->dev.klass.usb_desc = &s->desc; + s->dev.klass.product_desc = s->desc.str[2]; + + usb_desc_init(&s->dev); + usb_ep_init(&s->dev); + + return &s->dev; + fail: + usb_hid_unrealize(&s->dev); + return nullptr; + } + + void GunCon2Device::UpdateSettings(USBDevice* dev, SettingsInterface& si) const + { + GunCon2State* s = USB_CONTAINER_OF(dev, GunCon2State, dev); + + s->custom_config = USB::GetConfigBool(si, s->port, TypeName(), "custom_config", false); + + // Don't override auto config if we've set it. + if (!s->auto_config_done || s->custom_config) + { + s->screen_width = USB::GetConfigInt(si, s->port, TypeName(), "screen_width", DEFAULT_SCREEN_WIDTH); + s->screen_height = USB::GetConfigInt(si, s->port, TypeName(), "screen_height", DEFAULT_SCREEN_HEIGHT); + s->center_x = USB::GetConfigFloat(si, s->port, TypeName(), "center_x", DEFAULT_CENTER_X); + s->center_y = USB::GetConfigFloat(si, s->port, TypeName(), "center_y", DEFAULT_CENTER_Y); + s->scale_x = USB::GetConfigFloat(si, s->port, TypeName(), "scale_x", DEFAULT_SCALE_X) / 100.0f; + s->scale_y = USB::GetConfigFloat(si, s->port, TypeName(), "scale_y", DEFAULT_SCALE_Y) / 100.0f; + } + } + + float GunCon2Device::GetBindingValue(const USBDevice* dev, u32 bind_index) const + { + GunCon2State* s = USB_CONTAINER_OF(dev, GunCon2State, dev); + + const u32 bit = 1u << bind_index; + return ((s->button_state & bit) != 0) ? 1.0f : 0.0f; + } + + void GunCon2Device::SetBindingValue(USBDevice* dev, u32 bind_index, float value) const + { + GunCon2State* s = USB_CONTAINER_OF(dev, GunCon2State, dev); + + const u32 bit = 1u << bind_index; + if (value >= 0.5f) + s->button_state |= bit; + else + s->button_state &= ~bit; + } + + gsl::span GunCon2Device::Bindings(u32 subtype) const + { + static constexpr const InputBindingInfo bindings[] = { + //{"pointer", "Pointer/Aiming", InputBindingInfo::Type::Pointer, BID_POINTER_X, GenericInputBinding::Unknown}, + {"Up", "D-Pad Up", InputBindingInfo::Type::Button, BID_DPAD_UP, GenericInputBinding::DPadUp}, + {"Down", "D-Pad Down", InputBindingInfo::Type::Button, BID_DPAD_DOWN, GenericInputBinding::DPadDown}, + {"Left", "D-Pad Left", InputBindingInfo::Type::Button, BID_DPAD_LEFT, GenericInputBinding::DPadLeft}, + {"Right", "D-Pad Right", InputBindingInfo::Type::Button, BID_DPAD_RIGHT, + GenericInputBinding::DPadRight}, + {"Trigger", "Trigger", InputBindingInfo::Type::Button, BID_TRIGGER, GenericInputBinding::R2}, + {"ShootOffscreen", "Shoot Offscreen", InputBindingInfo::Type::Button, BID_SHOOT_OFFSCREEN, + GenericInputBinding::R1}, + {"Recalibrate", "Calibration Shot", InputBindingInfo::Type::Button, BID_RECALIBRATE, + GenericInputBinding::Unknown}, + {"A", "A", InputBindingInfo::Type::Button, BID_A, GenericInputBinding::Cross}, + {"B", "B", InputBindingInfo::Type::Button, BID_B, GenericInputBinding::Circle}, + {"C", "C", InputBindingInfo::Type::Button, BID_C, GenericInputBinding::Triangle}, + {"Select", "Select", InputBindingInfo::Type::Button, BID_SELECT, GenericInputBinding::Select}, + {"Start", "Start", InputBindingInfo::Type::Button, BID_START, GenericInputBinding::Start}, + }; + + return bindings; + } + + gsl::span GunCon2Device::Settings(u32 subtype) const + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::Boolean, "custom_config", "Manual Screen Configuration", + "Forces the use of the screen parameters below, instead of automatic parameters if available.", + "false"}, + {SettingInfo::Type::Float, "scale_x", "X Scale (Sensitivity)", + "Scales the position to simulate CRT curvature.", "100", "0", "100", "0.1", "%.2f%%", nullptr, nullptr, + 1.0f}, + {SettingInfo::Type::Float, "scale_y", "Y Scale (Sensitivity)", + "Scales the position to simulate CRT curvature.", "100", "0", "100", "0.1", "%.2f%%", nullptr, nullptr, + 1.0f}, + {SettingInfo::Type::Float, "center_x", "Center X", "Sets the center position of the simulated screen.", + "320", "0", "1024", "1", "%.0fpx", nullptr, nullptr, 1.0f}, + {SettingInfo::Type::Float, "center_y", "Center Y", "Sets the center position of the simulated screen.", + "120", "0", "1024", "1", "%.0fpx", nullptr, nullptr, 1.0f}, + {SettingInfo::Type::Integer, "screen_width", "Screen Width", "Sets the width of the simulated screen.", + "640", "1", "1024", "1", "%dpx", nullptr, nullptr, 1.0f}, + {SettingInfo::Type::Integer, "screen_height", "Screen Height", "Sets the height of the simulated screen.", + "240", "1", "1024", "1", "%dpx", nullptr, nullptr, 1.0f}, + }; + return info; + } + + bool GunCon2Device::Freeze(USBDevice* dev, StateWrapper& sw) const + { + GunCon2State* s = USB_CONTAINER_OF(dev, GunCon2State, dev); + + if (!sw.DoMarker("GunCon2Device")) + return false; + + sw.Do(&s->param_x); + sw.Do(&s->param_y); + sw.Do(&s->param_mode); + sw.Do(&s->calibration_timer); + sw.Do(&s->calibration_pos_x); + sw.Do(&s->calibration_pos_y); + sw.Do(&s->auto_config_done); + + float scale_x = s->scale_x; + float scale_y = s->scale_y; + float center_x = s->center_x; + float center_y = s->center_y; + u32 screen_width = s->screen_width; + u32 screen_height = s->screen_height; + sw.Do(&scale_x); + sw.Do(&scale_y); + sw.Do(¢er_x); + sw.Do(¢er_y); + sw.Do(&screen_width); + sw.Do(&screen_height); + + // Only save automatic settings to state. + if (sw.IsReading() && !s->custom_config && s->auto_config_done) + { + s->scale_x = scale_x; + s->scale_y = scale_y; + s->center_x = center_x; + s->center_y = center_y; + s->screen_width = screen_width; + s->screen_height = screen_height; + } + + return !sw.HasError(); + } +} // namespace usb_lightgun diff --git a/pcsx2/USB/usb-lightgun/guncon2.h b/pcsx2/USB/usb-lightgun/guncon2.h new file mode 100644 index 0000000000..7300680504 --- /dev/null +++ b/pcsx2/USB/usb-lightgun/guncon2.h @@ -0,0 +1,34 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once +#include "USB/deviceproxy.h" + +namespace usb_lightgun +{ + class GunCon2Device final : public DeviceProxy + { + public: + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* Name() const override; + const char* TypeName() const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override; + float GetBindingValue(const USBDevice* dev, u32 bind_index) const override; + void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override; + gsl::span Bindings(u32 subtype) const override; + gsl::span Settings(u32 subtype) const override; + }; +} // namespace usb_lightgun diff --git a/pcsx2/USB/usb-mic/api_init_linux.cpp b/pcsx2/USB/usb-mic/api_init_linux.cpp deleted file mode 100644 index 9c39b4ebdc..0000000000 --- a/pcsx2/USB/usb-mic/api_init_linux.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "audiodeviceproxy.h" -#include "audiodev-noop.h" -#ifdef SPU2X_PULSEAUDIO -#include "audiodev-pulse.h" -#endif - -void usb_mic::RegisterAudioDevice::Register() -{ - auto& inst = RegisterAudioDevice::instance(); - inst.Add(audiodev_noop::APINAME, new AudioDeviceProxy()); -#ifdef SPU2X_PULSEAUDIO - inst.Add(audiodev_pulse::APINAME, new AudioDeviceProxy()); -#endif -} diff --git a/pcsx2/USB/usb-mic/api_init_win32_mic.cpp b/pcsx2/USB/usb-mic/api_init_win32_mic.cpp deleted file mode 100644 index 87dc7a0214..0000000000 --- a/pcsx2/USB/usb-mic/api_init_win32_mic.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "audiodeviceproxy.h" -#include "audiodev-noop.h" -#include "audiodev-wasapi.h" - -void usb_mic::RegisterAudioDevice::Register() -{ - auto& inst = RegisterAudioDevice::instance(); - inst.Add(audiodev_noop::APINAME, new AudioDeviceProxy()); - inst.Add(audiodev_wasapi::APINAME, new AudioDeviceProxy()); -} diff --git a/pcsx2/USB/usb-mic/audiodev-cubeb.cpp b/pcsx2/USB/usb-mic/audiodev-cubeb.cpp new file mode 100644 index 0000000000..118d542689 --- /dev/null +++ b/pcsx2/USB/usb-mic/audiodev-cubeb.cpp @@ -0,0 +1,286 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "USB/usb-mic/audiodev-cubeb.h" +#include "USB/USB.h" +#include "common/Assertions.h" +#include "common/Console.h" + +#include "cubeb/cubeb.h" +#include "fmt/format.h" + +// Since the context gets used to populate the device list, that unfortunately means +// we need locking around it, since the UI thread's gonna be saying hi. The settings +// callbacks don't actually modify the context itself, though, only look at the +// device list. +static cubeb* s_cubeb_context; +static cubeb_device_collection s_cubeb_input_devices; +static cubeb_device_collection s_cubeb_output_devices; +static u32 s_cubeb_refcount = 0; +static std::mutex s_cubeb_context_mutex; + +static cubeb* GetCubebContext(const char* backend = nullptr) +{ + std::unique_lock lock(s_cubeb_context_mutex); + + if (!s_cubeb_context) + { + pxAssert(s_cubeb_refcount == 0); + const int res = cubeb_init(&s_cubeb_context, "PCSX2_USB", backend); + if (res != CUBEB_OK) + { + Console.Error("cubeb_init() failed: %d", res); + return nullptr; + } + + cubeb_enumerate_devices(s_cubeb_context, CUBEB_DEVICE_TYPE_INPUT, &s_cubeb_input_devices); + cubeb_enumerate_devices(s_cubeb_context, CUBEB_DEVICE_TYPE_OUTPUT, &s_cubeb_output_devices); + } + + if (s_cubeb_context) + s_cubeb_refcount++; + + return s_cubeb_context; +} + +static void ReleaseCubebContext() +{ + std::unique_lock lock(s_cubeb_context_mutex); + + pxAssert(s_cubeb_refcount > 0); + if ((--s_cubeb_refcount) == 0) + { + cubeb_device_collection_destroy(s_cubeb_context, &s_cubeb_input_devices); + s_cubeb_input_devices = {}; + cubeb_device_collection_destroy(s_cubeb_context, &s_cubeb_output_devices); + s_cubeb_output_devices = {}; + + cubeb_destroy(s_cubeb_context); + s_cubeb_context = nullptr; + } +} + +static cubeb_devid FindCubebDevice(const char* devname, bool input) +{ + if (std::strcmp(devname, "cubeb_default") == 0) + return nullptr; + + const cubeb_device_collection& col = input ? s_cubeb_input_devices : s_cubeb_output_devices; + for (size_t i = 0; i < col.count; i++) + { + if (std::strcmp(devname, col.device[i].device_id) == 0) + return col.device[i].devid; + } + + Console.Warning("(audiodev_cubeb) Unable to find %s device %s", input ? "input" : "output", devname); + return nullptr; +} + +static void CubebStateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state) +{ +} + +namespace usb_mic +{ + namespace audiodev_cubeb + { + CubebAudioDevice::CubebAudioDevice(u32 port, AudioDir dir, u32 channels, std::string devname, s32 latency) + : AudioDevice(port, dir, channels) + , mLatency(latency) + , mDeviceName(std::move(devname)) + { + mContext = GetCubebContext(); + mDeviceId = FindCubebDevice(mDeviceName.c_str(), (dir == AUDIODIR_SOURCE)); + } + + CubebAudioDevice::~CubebAudioDevice() + { + if (mStream) + CubebAudioDevice::Stop(); + + if (mContext) + ReleaseCubebContext(); + } + + std::vector> CubebAudioDevice::GetDeviceList(bool input) + { + std::vector> ret; + ret.emplace_back("", "Not Connected"); + ret.emplace_back("cubeb_default", input ? "Default Input Device" : "Default Output Device"); + if (GetCubebContext()) + { + const cubeb_device_collection& col = input ? s_cubeb_input_devices : s_cubeb_output_devices; + for (size_t i = 0; i < col.count; i++) + ret.emplace_back(col.device[i].device_id, col.device[i].friendly_name); + + ReleaseCubebContext(); + } + return ret; + } + + bool CubebAudioDevice::Start() + { + if (mStream) + Stop(); + + if (!mDeviceName.empty() && mDeviceName != "cubeb_default" && !mDeviceId) + { + Console.Error("(audiodev_cubeb) Device '%s' is not available.", mDeviceName.c_str()); + return false; + } + + cubeb_stream_params params; + params.format = CUBEB_SAMPLE_S16LE; + params.rate = mSampleRate; + params.channels = mChannels; + params.layout = CUBEB_LAYOUT_UNDEFINED; + params.prefs = CUBEB_STREAM_PREF_NONE; + + // Prefer minimum latency, reduces the chance of dropped samples due to the extra buffer. + u32 streamLatency; + if (cubeb_get_min_latency(mContext, ¶ms, &streamLatency) != CUBEB_OK) + streamLatency = mLatency; + + const bool input = (mAudioDir == AUDIODIR_SOURCE); + int res = cubeb_stream_init(mContext, &mStream, fmt::format("{}", (void*)this).c_str(), + input ? mDeviceId : nullptr, input ? ¶ms : nullptr, input ? nullptr : mDeviceId, + input ? nullptr : ¶ms, (streamLatency * mSampleRate) / 1000u, + &CubebAudioDevice::DataCallback, &CubebStateCallback, this); + if (res != CUBEB_OK) + { + Console.Error("(audiodev_cubeb) cubeb_stream_init() failed: %d", res); + return false; + } + + res = cubeb_stream_start(mStream); + if (res != CUBEB_OK) + { + Console.Error("(audiodev_cubeb) cubeb_stream_start() failed: %d", res); + cubeb_stream_destroy(mStream); + mStream = nullptr; + return false; + } + + ResetBuffers(); + return true; + } + + void CubebAudioDevice::Stop() + { + if (!mStream) + return; + + int res = cubeb_stream_stop(mStream); + if (res != CUBEB_OK) + Console.Error("cubeb_stream_stop() returned %d", res); + + cubeb_stream_destroy(mStream); + mStream = nullptr; + } + + uint32_t CubebAudioDevice::GetBuffer(short* buff, uint32_t frames) + { + if (!mStream) + return frames; + + std::lock_guard lk(mMutex); + u32 samples_to_read = frames * GetChannels(); + short* pDst = (short*)buff; + pxAssert(samples_to_read <= mBuffer.size()); + + while (samples_to_read > 0) + { + u32 samples = std::min(samples_to_read, static_cast(mBuffer.peek_read())); + if (!samples) + break; + memcpy(pDst, mBuffer.front(), samples * sizeof(short)); + mBuffer.read(samples); + pDst += samples; + samples_to_read -= samples; + } + return (frames - (samples_to_read / GetChannels())); + } + + uint32_t CubebAudioDevice::SetBuffer(short* buff, uint32_t frames) + { + if (!mStream) + return frames; + + std::lock_guard lk(mMutex); + size_t nbytes = frames * sizeof(short) * GetChannels(); + mBuffer.write((uint8_t*)buff, nbytes); + + return frames; + } + + bool CubebAudioDevice::GetFrames(uint32_t* size) + { + if (!mStream) + return true; + + std::lock_guard lk(mMutex); + *size = mBuffer.size() / GetChannels(); + return true; + } + + void CubebAudioDevice::SetResampling(int samplerate) + { + const bool was_started = (mStream != nullptr); + + Stop(); + + mSampleRate = samplerate; + + if (was_started) + Start(); + + ResetBuffers(); + } + + bool CubebAudioDevice::Compare(AudioDevice* compare) const + { + if (compare) + { + CubebAudioDevice* src = static_cast(compare); + if (src && mDeviceName == src->mDeviceName) + return true; + } + return false; + } + + void CubebAudioDevice::ResetBuffers() + { + // TODO: Do we want to make the buffer size adjustable? Currently 100ms max. + std::lock_guard lk(mMutex); + const u32 samples = ((mSampleRate * mChannels) * mLatency) / 1000u; + mBuffer.reserve(sizeof(u16) * samples); + } + + long CubebAudioDevice::DataCallback( + cubeb_stream* stream, void* user_ptr, void const* input_buffer, void* output_buffer, long nframes) + { + CubebAudioDevice* const ad = static_cast(user_ptr); + const size_t bytes = ad->mChannels * sizeof(short) * static_cast(nframes); + + std::lock_guard lk(ad->mMutex); + if (ad->mAudioDir == AUDIODIR_SOURCE) + ad->mBuffer.write((u8*)input_buffer, bytes); + else + ad->mBuffer.read((u8*)output_buffer, bytes); + + return nframes; + } + } // namespace audiodev_cubeb +} // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/audiodev-cubeb.h b/pcsx2/USB/usb-mic/audiodev-cubeb.h new file mode 100644 index 0000000000..0882ddbe5a --- /dev/null +++ b/pcsx2/USB/usb-mic/audiodev-cubeb.h @@ -0,0 +1,64 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "USB/shared/ringbuffer.h" +#include "USB/USB.h" +#include "audiodev.h" + +#include +#include +#include + +struct cubeb; +struct cubeb_stream; + +namespace usb_mic +{ + namespace audiodev_cubeb + { + class CubebAudioDevice final : public AudioDevice + { + public: + CubebAudioDevice(u32 port, AudioDir dir, u32 channels, std::string devname, s32 latency); + ~CubebAudioDevice(); + + static std::vector> GetDeviceList(bool input); + + uint32_t GetBuffer(short* buff, uint32_t frames) override; + uint32_t SetBuffer(short* buff, uint32_t frames) override; + bool GetFrames(uint32_t* size) override; + void SetResampling(int samplerate) override; + bool Start() override; + void Stop() override; + bool Compare(AudioDevice* compare) const override; + + protected: + void ResetBuffers(); + + static long DataCallback(struct cubeb_stream* stream, void* user_ptr, void const* input_buffer, + void* output_buffer, long nframes); + + u32 mSampleRate = 48000; + u32 mLatency = 50; + cubeb* mContext; + cubeb_stream* mStream = nullptr; + std::string mDeviceName; + const void* mDeviceId; + + RingBuffer mBuffer; + std::mutex mMutex; + }; + } // namespace audiodev_cubeb +} // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/audiodev-noop.h b/pcsx2/USB/usb-mic/audiodev-noop.h index 55f3687613..3e89dfbe1f 100644 --- a/pcsx2/USB/usb-mic/audiodev-noop.h +++ b/pcsx2/USB/usb-mic/audiodev-noop.h @@ -14,75 +14,37 @@ */ #pragma once -#include "audiodeviceproxy.h" +#include "audiodev.h" +#include namespace usb_mic { namespace audiodev_noop { - - static const char* APINAME = "noop"; - class NoopAudioDevice : public AudioDevice { public: - NoopAudioDevice(int port, const char* dev_type, int mic, AudioDir dir) - : AudioDevice(port, dev_type, mic, dir) + NoopAudioDevice( + u32 port, AudioDir dir, u32 channels) + : AudioDevice(port, dir, channels) { } - ~NoopAudioDevice() {} - void Start() {} - void Stop() {} - virtual bool GetFrames(uint32_t* size) + ~NoopAudioDevice() override {} + bool Start() override { return true; } - virtual uint32_t GetBuffer(int16_t* outBuf, uint32_t outFrames) + void Stop() override {} + bool GetFrames(uint32_t* size) override { return true; } + uint32_t GetBuffer(int16_t* outBuf, uint32_t outFrames) override { + std::memset(outBuf, 0, outFrames * sizeof(int16_t)); return outFrames; } - virtual uint32_t SetBuffer(int16_t* inBuf, uint32_t inFrames) - { - return inFrames; - } - virtual void SetResampling(int samplerate) {} - virtual uint32_t GetChannels() - { - return 1; - } + uint32_t SetBuffer(int16_t* inBuf, uint32_t inFrames) override { return inFrames; } + void SetResampling(int samplerate) override {} - virtual bool Compare(AudioDevice* compare) - { - return false; - } - - static const TCHAR* Name() - { - return TEXT("NOOP"); - } - - static bool AudioInit() - { - return true; - } - - static void AudioDeinit() - { - } - - static void AudioDevices(std::vector& devices, AudioDir) - { - AudioDeviceInfo info; - info.strID = TEXT("silence"); - info.strName = TEXT("Silence"); - devices.push_back(info); - } - - static int Configure(int port, const char* dev_type, void* data) - { - return RESULT_OK; - } + bool Compare(AudioDevice* compare) const override { return false; } }; - } // namespace audiodev_noop -} // namespace usb_mic +} // namespace usb_mic \ No newline at end of file diff --git a/pcsx2/USB/usb-mic/audiodev-pulse.cpp b/pcsx2/USB/usb-mic/audiodev-pulse.cpp deleted file mode 100644 index 44f9429934..0000000000 --- a/pcsx2/USB/usb-mic/audiodev-pulse.cpp +++ /dev/null @@ -1,895 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "USB/gtk.h" -#include "audiodev-pulse.h" -#ifdef DYNLINK_PULSE -#include "USB/dynlink/pulse.h" -#endif - -namespace usb_mic -{ - namespace audiodev_pulse - { - - static void pa_context_state_cb(pa_context* c, void* userdata) - { - pa_context_state_t state; - int* pa_ready = (int*)userdata; - - state = pa_context_get_state(c); - switch (state) - { - // There are just here for reference - case PA_CONTEXT_UNCONNECTED: - *pa_ready = 3; - break; - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - default: - break; - case PA_CONTEXT_FAILED: - case PA_CONTEXT_TERMINATED: - *pa_ready = 2; - break; - case PA_CONTEXT_READY: - *pa_ready = 1; - break; - } - } - - static void pa_sourcelist_cb(pa_context* c, const pa_source_info* l, int eol, void* userdata) - { - AudioDeviceInfoList* devicelist = static_cast(userdata); - - if (eol > 0) - { - return; - } - - AudioDeviceInfo dev; - dev.strID = l->name; - dev.strName = l->description; - //dev.intID = l->index; - devicelist->push_back(dev); - } - - static void pa_sinklist_cb(pa_context* c, const pa_sink_info* l, int eol, void* userdata) - { - AudioDeviceInfoList* devicelist = static_cast(userdata); - - if (eol > 0) - { - return; - } - - AudioDeviceInfo dev; - dev.strID = l->name; - dev.strName = l->description; - //dev.intID = l->index; - devicelist->push_back(dev); - } - - static int pa_get_devicelist(AudioDeviceInfoList& list, AudioDir dir) - { - pa_mainloop* pa_ml; - pa_mainloop_api* pa_mlapi; - pa_operation* pa_op; - pa_context* pa_ctx; - - int state = 0; - int pa_ready = 0; - - pa_ml = pa_mainloop_new(); - pa_mlapi = pa_mainloop_get_api(pa_ml); - pa_ctx = pa_context_new(pa_mlapi, "USB-devicelist"); - - pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); - - pa_context_set_state_callback(pa_ctx, pa_context_state_cb, &pa_ready); - - for (;;) - { - - if (pa_ready == 0) - { - pa_mainloop_iterate(pa_ml, 1, NULL); - continue; - } - - // Connection failed - if (pa_ready == 2) - { - pa_context_disconnect(pa_ctx); - pa_context_unref(pa_ctx); - pa_mainloop_free(pa_ml); - return -1; - } - - switch (state) - { - case 0: - if (dir == AUDIODIR_SOURCE) - pa_op = pa_context_get_source_info_list(pa_ctx, - pa_sourcelist_cb, - &list); - else - pa_op = pa_context_get_sink_info_list(pa_ctx, - pa_sinklist_cb, - &list); - state++; - break; - case 1: - if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) - { - pa_operation_unref(pa_op); - pa_context_disconnect(pa_ctx); - pa_context_unref(pa_ctx); - pa_mainloop_free(pa_ml); - return 0; - } - break; - default: - return -1; - } - pa_mainloop_iterate(pa_ml, 1, NULL); - } - } - - // GTK+ config. dialog stuff - static void populateDeviceWidget(GtkComboBox* widget, const std::string& devName, const AudioDeviceInfoList& devs) - { - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(widget))); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), "None"); - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); - - int i = 1; - for (auto& dev : devs) - { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), dev.strName.c_str()); - if (!devName.empty() && devName == dev.strID) - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), i); - i++; - } - } - - static void deviceChanged(GtkComboBox* widget, gpointer data) - { - *(int*)data = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - } - - static int GtkConfigure(int port, const char* dev_type, void* data) - { - GtkWidget* ro_frame; - - int dev_idxs[] = {0, 0, 0, 0}; - - AudioDeviceInfoList srcDevs; - if (pa_get_devicelist(srcDevs, AUDIODIR_SOURCE) != 0) - { - return RESULT_FAILED; - } - - AudioDeviceInfoList sinkDevs; - if (pa_get_devicelist(sinkDevs, AUDIODIR_SINK) != 0) - { - return RESULT_FAILED; - } - - GtkWidget* dlg = gtk_dialog_new_with_buttons( - "PulseAudio Settings", GTK_WINDOW(data), GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE); - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - - - GtkWidget* main_vbox = gtk_vbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(dlg_area_box), main_vbox, TRUE, FALSE, 5); - - ro_frame = gtk_frame_new("Audio Devices"); - gtk_box_pack_start(GTK_BOX(main_vbox), ro_frame, TRUE, FALSE, 5); - - GtkWidget* frame_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ro_frame), frame_vbox); - - const char* labels[] = {"Source 1", "Source 2", "Sink 1", "Sink 2"}; - for (int i = 0; i < 2; i++) - { - std::string devName; - LoadSetting(dev_type, port, APINAME, (i ? N_AUDIO_SOURCE1 : N_AUDIO_SOURCE0), devName); - - GtkWidget* cb = new_combobox(labels[i], frame_vbox); - g_signal_connect(G_OBJECT(cb), "changed", G_CALLBACK(deviceChanged), (gpointer)&dev_idxs[i]); - populateDeviceWidget(GTK_COMBO_BOX(cb), devName, srcDevs); - } - - //TODO only one for now - for (int i = 2; i < 3 /*4*/; i++) - { - std::string devName; - LoadSetting(dev_type, port, APINAME, (i - 2 ? N_AUDIO_SINK1 : N_AUDIO_SINK0), devName); - - GtkWidget* cb = new_combobox(labels[i], frame_vbox); - g_signal_connect(G_OBJECT(cb), "changed", G_CALLBACK(deviceChanged), (gpointer)&dev_idxs[i]); - populateDeviceWidget(GTK_COMBO_BOX(cb), devName, sinkDevs); - } - - ro_frame = gtk_frame_new("Buffer lengths"); - gtk_box_pack_start(GTK_BOX(main_vbox), ro_frame, TRUE, FALSE, 5); - - frame_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ro_frame), frame_vbox); - - const char* labels_buff[] = {"Sources", "Sinks"}; - const char* buff_var_name[] = {N_BUFFER_LEN_SRC, N_BUFFER_LEN_SINK}; - GtkWidget* scales[2]; - - GtkWidget* table = gtk_table_new(2, 2, true); - gtk_container_add(GTK_CONTAINER(frame_vbox), table); - gtk_table_set_homogeneous(GTK_TABLE(table), FALSE); - GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default - - for (int i = 0; i < 2; i++) - { - GtkWidget* label = gtk_label_new(labels_buff[i]); - gtk_table_attach(GTK_TABLE(table), label, - 0, 1, - 0 + i, 1 + i, - GTK_SHRINK, GTK_SHRINK, 5, 1); - - //scales[i] = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 1000, 1); - scales[i] = gtk_hscale_new_with_range(1, 1000, 1); - gtk_table_attach(GTK_TABLE(table), scales[i], - 1, 2, - 0 + i, 1 + i, - opt, opt, 5, 1); - - int32_t var; - if (LoadSetting(dev_type, port, APINAME, buff_var_name[i], var)) - gtk_range_set_value(GTK_RANGE(scales[i]), var); - else - gtk_range_set_value(GTK_RANGE(scales[i]), 50); - } - - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - - int scale_vals[2]; - for (int i = 0; i < 2; i++) - { - scale_vals[i] = gtk_range_get_value(GTK_RANGE(scales[i])); - } - - gtk_widget_destroy(dlg); - - // Wait for all gtk events to be consumed ... - while (gtk_events_pending()) - gtk_main_iteration_do(FALSE); - - int ret = RESULT_CANCELED; - if (result == GTK_RESPONSE_OK) - { - ret = RESULT_OK; - for (int i = 0; i < 2; i++) - { - int idx = dev_idxs[i]; - { - std::string var; - - if (idx > 0) - var = srcDevs[idx - 1].strID; - - if (!SaveSetting(dev_type, port, APINAME, (i ? N_AUDIO_SOURCE1 : N_AUDIO_SOURCE0), var)) - ret = RESULT_FAILED; - } - - idx = dev_idxs[i + 2]; - { - std::string var; - - if (idx > 0) - var = sinkDevs[idx - 1].strID; - - if (!SaveSetting(dev_type, port, APINAME, (i ? N_AUDIO_SINK1 : N_AUDIO_SINK0), var)) - ret = RESULT_FAILED; - } - - // Save buffer lengths - if (!SaveSetting(dev_type, port, APINAME, buff_var_name[i], scale_vals[i])) - ret = RESULT_FAILED; - } - } - - return ret; - } - - uint32_t PulseAudioDevice::GetBuffer(short* buff, uint32_t frames) - { - auto now = hrc::now(); - auto dur = std::chrono::duration_cast(now - mLastGetBuffer).count(); - - // init time point - if (mLastOut.time_since_epoch().count() == 0) - mLastOut = now; - - //Disconnected, try reconnect after every 1sec, hopefully game retries to read samples - if (mPAready == 3 && dur >= 1000) - { - mLastGetBuffer = now; - [[maybe_unused]] - int ret = pa_context_connect(mPContext, - mServer, - PA_CONTEXT_NOFLAGS, - NULL); - - //TODO reconnect stream as well? - - } - else - mLastGetBuffer = now; - - std::lock_guard lk(mMutex); - ssize_t samples_to_read = frames * GetChannels(); - short* pDst = (short*)buff; - assert(samples_to_read <= mOutBuffer.size()); - - while (samples_to_read > 0) - { - ssize_t samples = std::min(samples_to_read, (ssize_t)mOutBuffer.peek_read()); - if (!samples) - break; - memcpy(pDst, mOutBuffer.front(), samples * sizeof(short)); - mOutBuffer.read(samples); - pDst += samples; - samples_to_read -= samples; - } - return (frames - (samples_to_read / GetChannels())); - } - - uint32_t PulseAudioDevice::SetBuffer(short* buff, uint32_t frames) - { - auto now = hrc::now(); - auto dur = std::chrono::duration_cast(now - mLastGetBuffer).count(); - - // init time point - if (mLastOut.time_since_epoch().count() == 0) - mLastOut = now; - - //Disconnected, try reconnect after every 1sec - if (mPAready == 3 && dur >= 1000) - { - mLastGetBuffer = now; - int ret = pa_context_connect(mPContext, - mServer, - PA_CONTEXT_NOFLAGS, - NULL); - - //TODO reconnect stream as well? - - if (ret != PA_OK) - return frames; - } - else - mLastGetBuffer = now; - - std::lock_guard lk(mMutex); - size_t nbytes = frames * sizeof(short) * GetChannels(); - mInBuffer.write((uint8_t*)buff, nbytes); - - return frames; - } - - bool PulseAudioDevice::GetFrames(uint32_t* size) - { - std::lock_guard lk(mMutex); - *size = mOutBuffer.size() / GetChannels(); - return true; - } - - void PulseAudioDevice::SetResampling(int samplerate) - { - mSamplesPerSec = samplerate; - if (mAudioDir == AUDIODIR_SOURCE) - mResampleRatio = double(samplerate) / double(mSSpec.rate); - else - mResampleRatio = double(mSSpec.rate) / double(samplerate); - //mResample = true; - ResetBuffers(); - } - - void PulseAudioDevice::Start() - { - ResetBuffers(); - mPaused = false; - if (mStream) - { - pa_threaded_mainloop_lock(mPMainLoop); - if (pa_stream_is_corked(mStream) > 0) - { - pa_operation* op = pa_stream_cork(mStream, 0, stream_success_cb, this); - if (op) - pa_operation_unref(op); - } - pa_threaded_mainloop_unlock(mPMainLoop); - } - } - - void PulseAudioDevice::Stop() - { - mPaused = true; - if (mStream) - { - pa_threaded_mainloop_lock(mPMainLoop); - if (!pa_stream_is_corked(mStream)) - { - pa_operation* op = pa_stream_cork(mStream, 1, stream_success_cb, this); - if (op) - pa_operation_unref(op); - } - pa_threaded_mainloop_unlock(mPMainLoop); - } - } - - bool PulseAudioDevice::Compare(AudioDevice* compare) - { - if (compare) - { - PulseAudioDevice* src = static_cast(compare); - if (src && mDeviceName == src->mDeviceName) - return true; - } - return false; - } - - void PulseAudioDevice::Uninit() - { - if (mStream) - { - pa_threaded_mainloop_lock(mPMainLoop); - [[maybe_unused]]int ret = pa_stream_disconnect(mStream); - pa_stream_unref(mStream); - mStream = nullptr; - pa_threaded_mainloop_unlock(mPMainLoop); - } - if (mPMainLoop) - { - pa_threaded_mainloop_stop(mPMainLoop); - } - if (mPContext) - { - pa_context_disconnect(mPContext); - pa_context_unref(mPContext); - mPContext = nullptr; - } - if (mPMainLoop) - { - pa_threaded_mainloop_free(mPMainLoop); - mPMainLoop = nullptr; - } - } - - bool PulseAudioDevice::Init() - { - int ret = 0; - pa_operation* pa_op = nullptr; - - mPMainLoop = pa_threaded_mainloop_new(); - pa_mainloop_api* mlapi = pa_threaded_mainloop_get_api(mPMainLoop); - - mPContext = pa_context_new(mlapi, "USB"); - - pa_context_set_state_callback(mPContext, - context_state_cb, - this); - - // Lock the mainloop so that it does not run and crash before the context is ready - pa_threaded_mainloop_lock(mPMainLoop); - pa_threaded_mainloop_start(mPMainLoop); - - ret = pa_context_connect(mPContext, - mServer, - PA_CONTEXT_NOFLAGS, - NULL); - - if (ret != PA_OK) - goto unlock_and_fail; - - // wait for pa_context_state_cb - for (;;) - { - if (mPAready == 1) - break; - if (mPAready == 2 || mQuit) - goto unlock_and_fail; - pa_threaded_mainloop_wait(mPMainLoop); - } - - mStream = pa_stream_new(mPContext, - "USB-pulse", - &mSSpec, - NULL); - - if (!mStream) - goto unlock_and_fail; - - pa_stream_set_state_callback(mStream, stream_state_cb, this); - - // Sets individual read callback fragsize but recording itself - // still "lags" ~1sec (read_cb is called in bursts) without - // PA_STREAM_ADJUST_LATENCY - pa_buffer_attr buffer_attr; - buffer_attr.maxlength = (uint32_t)-1; - buffer_attr.tlength = (uint32_t)-1; - buffer_attr.prebuf = (uint32_t)-1; - buffer_attr.minreq = (uint32_t)-1; - buffer_attr.fragsize = pa_usec_to_bytes(mBuffering * 1000, &mSSpec); - - if (mAudioDir == AUDIODIR_SOURCE) - { - pa_stream_set_read_callback(mStream, - stream_read_cb, - this); - - ret = pa_stream_connect_record(mStream, - mDeviceName.c_str(), - &buffer_attr, - PA_STREAM_ADJUST_LATENCY); - } - else - { - pa_stream_set_write_callback(mStream, - stream_write_cb, - this); - - buffer_attr.maxlength = pa_bytes_per_second(&mSSpec); - buffer_attr.prebuf = 0; // Don't stop on underrun but then - // stream also only starts manually with uncorking. - buffer_attr.tlength = pa_usec_to_bytes(mBuffering * 1000, &mSSpec); - pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING | - PA_STREAM_NOT_MONOTONIC | - PA_STREAM_AUTO_TIMING_UPDATE | - //PA_STREAM_VARIABLE_RATE | - PA_STREAM_ADJUST_LATENCY); - - ret = pa_stream_connect_playback(mStream, - mDeviceName.c_str(), - &buffer_attr, - flags, - nullptr, - nullptr); - } - - if (ret != PA_OK) - goto unlock_and_fail; - - // Wait for the stream to be ready - for (;;) - { - pa_stream_state_t stream_state = pa_stream_get_state(mStream); - assert(PA_STREAM_IS_GOOD(stream_state)); - if (stream_state == PA_STREAM_READY) - break; - if (stream_state == PA_STREAM_FAILED) - goto unlock_and_fail; - pa_threaded_mainloop_wait(mPMainLoop); - } - - - pa_op = pa_stream_cork(mStream, 0, stream_success_cb, this); - if (pa_op) - pa_operation_unref(pa_op); - - pa_threaded_mainloop_unlock(mPMainLoop); - - pa_op = pa_stream_update_timing_info(mStream, stream_success_cb, nullptr); - if (pa_op) - pa_operation_unref(pa_op); - //const pa_timing_info* pa_ti = pa_stream_get_timing_info(mStream); - - pa_usec_t r_usec; - int negative; - ret = pa_stream_get_latency(mStream, &r_usec, &negative); - - // Setup resampler - mResampler = src_delete(mResampler); - - mResampler = src_new(SRC_SINC_FASTEST, GetChannels(), &ret); - if (!mResampler) - { - goto error; - } - - mLastGetBuffer = hrc::now(); - return true; - unlock_and_fail: - pa_threaded_mainloop_unlock(mPMainLoop); - error: - Uninit(); - return false; - } - - void PulseAudioDevice::ResetBuffers() - { - size_t bytes; - std::lock_guard lk(mMutex); - pa_sample_spec ss(mSSpec); - ss.rate = mSamplesPerSec; - - if (mAudioDir == AUDIODIR_SOURCE) - { - bytes = pa_bytes_per_second(&mSSpec) * mBuffering / 1000; - bytes += bytes % pa_frame_size(&mSSpec); //align just in case - mInBuffer.reserve(bytes); - - bytes = pa_bytes_per_second(&ss) * mBuffering / 1000; - bytes += bytes % pa_frame_size(&ss); - mOutBuffer.reserve(bytes); - } - else - { - bytes = pa_bytes_per_second(&mSSpec) * mBuffering / 1000; - bytes += bytes % pa_frame_size(&mSSpec); - mOutBuffer.reserve(bytes); - - bytes = pa_bytes_per_second(&ss) * mBuffering / 1000; - bytes += bytes % pa_frame_size(&ss); - mInBuffer.reserve(bytes); - } - - src_reset(mResampler); - } - - int PulseAudioDevice::Configure(int port, const char* dev_type, void* data) - { - int ret = RESULT_FAILED; - if (PulseAudioDevice::AudioInit()) - { - ret = GtkConfigure(port, dev_type, data); - PulseAudioDevice::AudioDeinit(); - } - return ret; - } - - void PulseAudioDevice::AudioDevices(std::vector& devices, AudioDir& dir) - { - pa_get_devicelist(devices, dir); - } - - bool PulseAudioDevice::AudioInit() - { -#ifdef DYNLINK_PULSE - return DynLoadPulse(); -#else - return true; -#endif - } - - void PulseAudioDevice::AudioDeinit() - { -#ifdef DYNLINK_PULSE - DynUnloadPulse(); -#endif - } - - void PulseAudioDevice::context_state_cb(pa_context* c, void* userdata) - { - pa_context_state_t state; - PulseAudioDevice* padev = (PulseAudioDevice*)userdata; - - state = pa_context_get_state(c); - switch (state) - { - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - default: - break; - case PA_CONTEXT_UNCONNECTED: - padev->mPAready = 3; - break; - case PA_CONTEXT_FAILED: - case PA_CONTEXT_TERMINATED: - padev->mPAready = 2; - break; - case PA_CONTEXT_READY: - padev->mPAready = 1; - break; - } - - pa_threaded_mainloop_signal(padev->mPMainLoop, 0); - } - - void PulseAudioDevice::stream_state_cb(pa_stream* s, void* userdata) - { - PulseAudioDevice* padev = (PulseAudioDevice*)userdata; - pa_threaded_mainloop_signal(padev->mPMainLoop, 0); - } - - void PulseAudioDevice::stream_read_cb(pa_stream* p, size_t nbytes, void* userdata) - { - std::vector rebuf; - SRC_DATA data; - PulseAudioDevice* padev = (PulseAudioDevice*)userdata; - const void* padata = NULL; - - if (padev->mQuit) - return; - - - int ret = pa_stream_peek(p, &padata, &nbytes); - - if (ret != PA_OK) - return; - - //auto dur = std::chrono::duration_cast(hrc::now() - padev->mLastGetBuffer).count(); - if (padev->mPaused /*|| dur > 5000*/ || (!padata && nbytes /* hole */)) - { - ret = pa_stream_drop(p); - return; - } - - std::lock_guard lock(padev->mMutex); - - padev->mInBuffer.write((uint8_t*)padata, nbytes); - - //if copy succeeded, drop samples at pulse's side - ret = pa_stream_drop(p); - - size_t resampled = static_cast(padev->mInBuffer.size() * padev->mResampleRatio * padev->mTimeAdjust); - if (resampled == 0) - resampled = padev->mInBuffer.size(); - rebuf.resize(resampled); - - size_t output_frames_gen = 0, input_frames_used = 0; - float* pBegin = rebuf.data(); - float* pEnd = pBegin + rebuf.size(); - - memset(&data, 0, sizeof(SRC_DATA)); - - while (padev->mInBuffer.peek_read() > 0) - { - data.data_in = (float*)padev->mInBuffer.front(); - data.input_frames = padev->mInBuffer.peek_read() / padev->GetChannels(); - data.data_out = pBegin; - data.output_frames = (pEnd - pBegin) / padev->GetChannels(); - data.src_ratio = padev->mResampleRatio * padev->mTimeAdjust; - - src_process(padev->mResampler, &data); - output_frames_gen += data.output_frames_gen; - pBegin += data.output_frames_gen * padev->GetChannels(); - input_frames_used += data.input_frames_used; - - size_t samples = data.input_frames_used * padev->GetChannels(); - if (!samples) - break; //TODO happens? - padev->mInBuffer.read(samples); - } - - size_t output_samples = output_frames_gen * padev->GetChannels(); - float* pSrc = rebuf.data(); - while (output_samples > 0) - { - size_t samples = std::min(output_samples, padev->mOutBuffer.peek_write(true)); - src_float_to_short_array(pSrc, padev->mOutBuffer.back(), samples); - padev->mOutBuffer.write(samples); - output_samples -= samples; - pSrc += samples; - } - } - - void PulseAudioDevice::stream_write_cb(pa_stream* p, size_t nbytes, void* userdata) - { - void* pa_buffer = NULL; - size_t pa_bytes; - // The length of the data to write in bytes, must be in multiples of the stream's sample spec frame size - ssize_t remaining_bytes = nbytes; - int ret = PA_OK; - std::vector inFloats; - SRC_DATA data; - memset(&data, 0, sizeof(SRC_DATA)); - - PulseAudioDevice* padev = (PulseAudioDevice*)userdata; - if (padev->mQuit) - return; - - { - std::lock_guard lock(padev->mMutex); - // Convert short samples to float and to final output sample rate - if (padev->mInBuffer.size() > 0) - { - inFloats.resize(padev->mInBuffer.size()); - float* pDst = inFloats.data(); - - while (padev->mInBuffer.peek_read() > 0) - { - size_t samples = padev->mInBuffer.peek_read(); - src_short_to_float_array( - (const short*)padev->mInBuffer.front(), - pDst, samples); - pDst += samples; - padev->mInBuffer.read(samples); - } - - size_t input_frames_used = 0; - size_t in_offset = 0; - while (padev->mOutBuffer.peek_write() > 0) - { - data.data_in = inFloats.data() + in_offset; - data.input_frames = (inFloats.size() - in_offset) / padev->GetChannels(); - data.data_out = padev->mOutBuffer.back(); - data.output_frames = padev->mOutBuffer.peek_write() / padev->GetChannels(); - data.src_ratio = padev->mResampleRatio * padev->mTimeAdjust; - - src_process(padev->mResampler, &data); - - input_frames_used += data.input_frames_used; - in_offset = input_frames_used * padev->GetChannels(); - - padev->mOutBuffer.write(data.output_frames_gen * padev->GetChannels()); - - if (inFloats.size() <= in_offset || data.output_frames_gen == 0) - break; - } - } - } - - // Write converted float samples or silence to PulseAudio stream - while (remaining_bytes > 0) - { - pa_bytes = remaining_bytes; - - ret = pa_stream_begin_write(padev->mStream, &pa_buffer, &pa_bytes); - if (ret != PA_OK) - { - goto exit; - } - - ssize_t final_bytes = 0; - // read twice because possible wrap - while (padev->mOutBuffer.size() > 0) - { - ssize_t read = std::min((ssize_t)pa_bytes - final_bytes, (ssize_t)padev->mOutBuffer.peek_read()); - if (read <= 0) - break; - - memcpy((uint8_t*)pa_buffer + final_bytes, padev->mOutBuffer.front(), read); - final_bytes += read; - padev->mOutBuffer.read(read); - } - - if ((ssize_t)pa_bytes > final_bytes) - memset((uint8_t*)pa_buffer + final_bytes, 0, pa_bytes - final_bytes); - - ret = pa_stream_write(padev->mStream, pa_buffer, pa_bytes, NULL, 0LL, PA_SEEK_RELATIVE); - if (ret != PA_OK) - { - pa_stream_cancel_write(padev->mStream); //TODO needed? - goto exit; - } - - remaining_bytes -= pa_bytes; - } - - exit: - - return; - } - - } // namespace audiodev_pulse -} // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/audiodev-pulse.h b/pcsx2/USB/usb-mic/audiodev-pulse.h deleted file mode 100644 index b77796ee81..0000000000 --- a/pcsx2/USB/usb-mic/audiodev-pulse.h +++ /dev/null @@ -1,168 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include -#include -#include -#include "USB/shared/ringbuffer.h" -#include "audiodeviceproxy.h" -#include -//#include -//#include -#include -#include - -namespace usb_mic -{ - namespace audiodev_pulse - { - -// macros for string concat -#undef APINAME_ -#define APINAME_ "pulse" - - static const char* APINAME = "pulse"; - - using hrc = std::chrono::high_resolution_clock; - using ms = std::chrono::milliseconds; - using us = std::chrono::microseconds; - using ns = std::chrono::nanoseconds; - using sec = std::chrono::seconds; - - class PulseAudioDevice : public AudioDevice - { - public: - PulseAudioDevice(int port, const char* dev_type, int device, AudioDir dir) - : AudioDevice(port, dev_type, device, dir) - , mBuffering(50) - , mPaused(true) - , mQuit(false) - , mPMainLoop(nullptr) - , mPContext(nullptr) - , mStream(nullptr) - , mServer(nullptr) - , mPAready(0) - , mResampleRatio(1.0) - , mTimeAdjust(1.0) - , mSamplesPerSec(48000) - , mResampler(nullptr) - , mOutSamples(0) - { - int i = dir == AUDIODIR_SOURCE ? 0 : 2; - const char* var_names[] = { - N_AUDIO_SOURCE0, - N_AUDIO_SOURCE1, - N_AUDIO_SINK0, - N_AUDIO_SINK1}; - - if (!LoadSetting(mDevType, mPort, APINAME, (device ? var_names[i + 1] : var_names[i]), mDeviceName) || mDeviceName.empty()) - throw AudioDeviceError(APINAME_ ": failed to load device settings"); - - LoadSetting(mDevType, mPort, APINAME, (dir == AUDIODIR_SOURCE ? N_BUFFER_LEN_SRC : N_BUFFER_LEN_SINK), mBuffering); - mBuffering = MIN(1000, MAX(1, mBuffering)); - - if (!AudioInit()) - throw AudioDeviceError(APINAME_ ": failed to bind pulseaudio library"); - - mSSpec.format = PA_SAMPLE_FLOAT32LE; //PA_SAMPLE_S16LE; - mSSpec.channels = 2; - mSSpec.rate = 48000; - - if (!Init()) - throw AudioDeviceError(APINAME_ ": failed to init"); - } - - ~PulseAudioDevice() - { - mQuit = true; - std::lock_guard lock(mMutex); - Uninit(); - AudioDeinit(); - mResampler = src_delete(mResampler); - if (file) - fclose(file); - } - - uint32_t GetBuffer(short* buff, uint32_t frames); - uint32_t SetBuffer(short* buff, uint32_t frames); - bool GetFrames(uint32_t* size); - void SetResampling(int samplerate); - void Start(); - void Stop(); - virtual bool Compare(AudioDevice* compare); - void Uninit(); - bool Init(); - void ResetBuffers(); - - inline uint32_t GetChannels() - { - return mSSpec.channels; - } - - static const char* TypeName() - { - return APINAME; - } - - static const TCHAR* Name() - { - return "PulseAudio"; - } - - static int Configure(int port, const char* dev_type, void* data); - - static void AudioDevices(std::vector& devices, AudioDir& dir); - - static bool AudioInit(); - static void AudioDeinit(); - - static void context_state_cb(pa_context* c, void* userdata); - static void stream_state_cb(pa_stream* s, void* userdata); - static void stream_read_cb(pa_stream* p, size_t nbytes, void* userdata); - static void stream_write_cb(pa_stream* p, size_t nbytes, void* userdata); - static void stream_success_cb(pa_stream* p, int success, void* userdata) {} - - protected: - int mChannels; - int mBuffering; - std::string mDeviceName; - pa_sample_spec mSSpec; - - RingBuffer mOutBuffer; - RingBuffer mInBuffer; - //std::thread mThread; - //std::condition_variable mEvent; - std::mutex mMutex; - bool mPaused; - bool mQuit; - hrc::time_point mLastGetBuffer; - - pa_threaded_mainloop* mPMainLoop; - pa_context* mPContext; - pa_stream* mStream; - char* mServer; //TODO add server selector? - int mPAready; - double mResampleRatio; - // Speed up or slow down audio - double mTimeAdjust; - int mSamplesPerSec; - SRC_STATE* mResampler; - - int mOutSamples; - hrc::time_point mLastOut; - FILE* file = nullptr; - }; - } // namespace audiodev_pulse -} // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/audiodev-wasapi.cpp b/pcsx2/USB/usb-mic/audiodev-wasapi.cpp deleted file mode 100644 index 158e8cb776..0000000000 --- a/pcsx2/USB/usb-mic/audiodev-wasapi.cpp +++ /dev/null @@ -1,1019 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -// Used OBS as example - -#include "PrecompiledHeader.h" -#include -#include -#include -#include -#include -#include "audiodev-wasapi.h" -#include "USB/Win32/Config_usb.h" -#include "USB/Win32/resource_usb.h" - -#define SafeRelease(x) \ - if (x) \ - { \ - x->Release(); \ - x = NULL; \ - } -#define ConvertMSTo100NanoSec(ms) (ms * 1000 * 10) //1000 microseconds, then 10 "100nanosecond" segments - -namespace usb_mic -{ - namespace audiodev_wasapi - { - - static FILE* file = nullptr; - - //Config dlg temporaries - struct WASAPISettings - { - int port; - const char* dev_type; - AudioDeviceInfoList sourceDevs; - AudioDeviceInfoList sinkDevs; - std::wstring selectedDev[3]; - }; - - static BOOL CALLBACK WASAPIDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); - - LARGE_INTEGER clockFreq = {0}; - __declspec(thread) LONGLONG lastQPCTime = 0; - - LONGLONG GetQPCTimeMS() - { - LARGE_INTEGER currentTime; - QueryPerformanceCounter(¤tTime); - - if (currentTime.QuadPart < lastQPCTime) - - lastQPCTime = currentTime.QuadPart; - - LONGLONG timeVal = currentTime.QuadPart; - timeVal *= 1000; - timeVal /= clockFreq.QuadPart; - - return timeVal; - } - - LONGLONG GetQPCTime100NS() - { - LARGE_INTEGER currentTime; - QueryPerformanceCounter(¤tTime); - - lastQPCTime = currentTime.QuadPart; - - double timeVal = double(currentTime.QuadPart); - timeVal *= 10000000.0; - timeVal /= double(clockFreq.QuadPart); - - return LONGLONG(timeVal); - } - - MMAudioDevice::~MMAudioDevice() - { - mQuit = true; - if (mThread != INVALID_HANDLE_VALUE) - { - if (WaitForSingleObject(mThread, 30000) != WAIT_OBJECT_0) - TerminateThread(mThread, 0); - } - - FreeData(); - SafeRelease(mmEnumerator); - mResampler = src_delete(mResampler); - if (file) - fclose(file); - file = nullptr; - - CloseHandle(mThread); - mThread = INVALID_HANDLE_VALUE; - CloseHandle(mMutex); - mMutex = INVALID_HANDLE_VALUE; - } - - void MMAudioDevice::FreeData() - { - SafeRelease(mmCapture); - SafeRelease(mmRender); - SafeRelease(mmClient); - SafeRelease(mmDevice); - SafeRelease(mmClock); - //clear mBuffer - } - - bool MMAudioDevice::Init() - { - const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); - const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); - - if (mAudioDir == AUDIODIR_SOURCE) - { - if (!LoadSetting(mDevType, mPort, APINAME, (mDevice ? N_AUDIO_SOURCE1 : N_AUDIO_SOURCE0), mDevID)) - { - throw AudioDeviceError("MMAudioDevice:: failed to load source from ini!"); - } - } - else - { - if (!LoadSetting(mDevType, mPort, APINAME, (mDevice ? N_AUDIO_SINK1 : N_AUDIO_SINK0), mDevID)) - { - throw AudioDeviceError("MMAudioDevice:: failed to load sink from ini!"); - } - } - - if (!mDevID.length()) - return false; - - { - int var; - if (LoadSetting(mDevType, mPort, APINAME, (mAudioDir == AUDIODIR_SOURCE ? N_BUFFER_LEN_SRC : N_BUFFER_LEN_SINK), var)) - mBuffering = std::min(1000, std::max(1, var)); - } - - - HRESULT err = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&mmEnumerator); - if (FAILED(err)) - { - Console.WriteLn("MMAudioDevice::Init(): Could not create IMMDeviceEnumerator = %08lX\n", err); - return false; - } - //TODO Not starting thread here unnecesserily - //mThread = CreateThread(NULL, 0, MMAudioDevice::CaptureThread, this, 0, 0); - return true; - } - - bool MMAudioDevice::Reinitialize() - { - const IID IID_IAudioClient = __uuidof(IAudioClient); - const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient); - const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); - HRESULT err; - - if (!mDeviceLost && mmClock) - return true; - else - { - if (GetQPCTimeMS() - mLastTimeMS < 1000) - return false; - mLastTimeMS = GetQPCTimeMS(); - } - - err = mmEnumerator->GetDevice(mDevID.c_str(), &mmDevice); - - if (FAILED(err)) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Could not create IMMDevice = %08lX\n", err); - return false; - } - - err = mmDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&mmClient); - if (FAILED(err)) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Could not create IAudioClient = %08lX\n", err); - return false; - } - - // get name - - /*IPropertyStore *store; - if(SUCCEEDED(mmDevice->OpenPropertyStore(STGM_READ, &store))) - { - PROPVARIANT varName; - - PropVariantInit(&varName); - if(SUCCEEDED(store->GetValue(PKEY_Device_FriendlyName, &varName))) - { - const WCHAR* wstrName = varName.pwszVal; - mDeviceName = wstrName; - } - - store->Release(); - }*/ - - // get format - - WAVEFORMATEX* pwfx; - err = mmClient->GetMixFormat(&pwfx); - if (FAILED(err)) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Could not get mix format from audio client = %08lX\n", err); - return false; - } - - WAVEFORMATEXTENSIBLE* wfext = NULL; - - if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - { - wfext = (WAVEFORMATEXTENSIBLE*)pwfx; - mInputChannelMask = wfext->dwChannelMask; - - if (wfext->SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Unsupported wave format\n"); - CoTaskMemFree(pwfx); - return false; - } - } - else if (pwfx->wFormatTag != WAVE_FORMAT_IEEE_FLOAT) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Unsupported wave format\n"); - CoTaskMemFree(pwfx); - return false; - } - - mFloat = true; - mDeviceChannels = pwfx->nChannels; - mDeviceBitsPerSample = 32; - mDeviceBlockSize = pwfx->nBlockAlign; - mDeviceSamplesPerSec = pwfx->nSamplesPerSec; - //sampleWindowSize = (inputSamplesPerSec/100); - - DWORD flags = 0; //useInputDevice ? 0 : AUDCLNT_STREAMFLAGS_LOOPBACK; - - //Random limit of 1ms to 1 seconds - if (mBuffering == 0) - mBuffering = 50; - mBuffering = std::min(std::max(mBuffering, 1LL), 1000LL); - - err = mmClient->Initialize(AUDCLNT_SHAREMODE_SHARED, flags, ConvertMSTo100NanoSec(mBuffering), 0, pwfx, NULL); - //err = AUDCLNT_E_UNSUPPORTED_FORMAT; - - if (FAILED(err)) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Could not initialize audio client, result = %08lX\n", err); - CoTaskMemFree(pwfx); - return false; - } - - // acquire services - if (mAudioDir == AUDIODIR_SOURCE) - err = mmClient->GetService(IID_IAudioCaptureClient, (void**)&mmCapture); - else - err = mmClient->GetService(IID_IAudioRenderClient, (void**)&mmRender); - - if (FAILED(err)) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Could not get audio %s client, result = %08lX\n", - (mAudioDir == AUDIODIR_SOURCE ? TEXT("capture") : TEXT("render")), err); - CoTaskMemFree(pwfx); - return false; - } - - err = mmClient->GetService(__uuidof(IAudioClock), (void**)&mmClock); - - if (FAILED(err)) - { - if (!mDeviceLost) - Console.WriteLn("MMAudioDevice::Reinitialize(): Could not get audio capture clock, result = %08lX\n", err); - CoTaskMemFree(pwfx); - return false; - } - - CoTaskMemFree(pwfx); - - // Setup resampler - int converterType = SRC_SINC_FASTEST; - int errVal = 0; - - mResampler = src_delete(mResampler); - mResampler = src_new(converterType, mDeviceChannels, &errVal); - - if (!mResampler) - { -#ifndef _DEBUG - Console.WriteLn("USB: Failed to create resampler: error %08lX", errVal); -#endif - return false; - } - - ResetBuffers(); - - if (mDeviceLost && !mFirstSamples) //TODO really lost and just first run. Call Start() from ctor always anyway? - this->Start(); - - mDeviceLost = false; - - return true; - } - - void MMAudioDevice::Start() - { - src_reset(mResampler); - if (mmClient) - mmClient->Start(); - mPaused = false; - } - - void MMAudioDevice::Stop() - { - mPaused = true; - if (mmClient) - mmClient->Stop(); - } - - void MMAudioDevice::ResetBuffers() - { - if (WaitForSingleObject(mMutex, 5000) != WAIT_OBJECT_0) - { - return; - } - - size_t bytes; - if (mAudioDir == AUDIODIR_SOURCE) - { - bytes = mDeviceChannels * mDeviceSamplesPerSec * sizeof(float) * mBuffering / 1000; - bytes += bytes % (mDeviceChannels * sizeof(float)); - mInBuffer.reserve(bytes); - - bytes = mDeviceChannels * mSamplesPerSec * sizeof(short) * mBuffering / 1000; - bytes += bytes % (mDeviceChannels * sizeof(short)); - mOutBuffer.reserve(bytes); - } - else - { - bytes = mDeviceChannels * mDeviceSamplesPerSec * sizeof(float) * mBuffering / 1000; - bytes += bytes % (mDeviceChannels * sizeof(float)); - mOutBuffer.reserve(bytes); - - bytes = mDeviceChannels * mSamplesPerSec * sizeof(short) * mBuffering / 1000; - bytes += bytes % (mDeviceChannels * sizeof(short)); - mInBuffer.reserve(bytes); - } - - ReleaseMutex(mMutex); - } - - //TODO or just return samples count in mOutBuffer? - bool MMAudioDevice::GetFrames(uint32_t* size) - { - if (WaitForSingleObject(mMutex, 5000) != WAIT_OBJECT_0) - { - *size = 0; - return false; - } - *size = mOutBuffer.size() / mDeviceChannels; - ReleaseMutex(mMutex); - return true; - } - - unsigned WINAPI MMAudioDevice::CaptureThread(LPVOID ptr) - { - MMAudioDevice* src = (MMAudioDevice*)ptr; - std::vector rebuf; - unsigned ret = 1; - bool bThreadComInitialized = false; - - //TODO APARTMENTTHREADED instead? - HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if ((S_OK != hr) && (S_FALSE != hr) /* already inited */ && (hr != RPC_E_CHANGED_MODE)) - { - goto error; - } - - if (hr != RPC_E_CHANGED_MODE) - bThreadComInitialized = true; - - //Call mmClient->Start() here instead? - - while (!src->mQuit) - { - while (src->mPaused) - { - Sleep(100); - if (src->mQuit) - goto quit; - } - - src->GetMMBuffer(); - if (src->mInBuffer.size()) - { - size_t resampled = static_cast(src->mInBuffer.size() * src->mResampleRatio * src->mTimeAdjust); - if (resampled == 0) - resampled = src->mInBuffer.size(); - rebuf.resize(resampled); - - SRC_DATA srcData; - memset(&srcData, 0, sizeof(SRC_DATA)); - size_t output_frames = 0; - float* pBegin = rebuf.data(); - float* pEnd = pBegin + rebuf.size(); - - memset(&srcData, 0, sizeof(SRC_DATA)); - - while (src->mInBuffer.peek_read() > 0) - { - srcData.data_in = src->mInBuffer.front(); - srcData.input_frames = src->mInBuffer.peek_read() / src->GetChannels(); - srcData.data_out = pBegin; - srcData.output_frames = (pEnd - pBegin) / src->GetChannels(); - srcData.src_ratio = src->mResampleRatio * src->mTimeAdjust; - - src_process(src->mResampler, &srcData); - output_frames += srcData.output_frames_gen; - pBegin += srcData.output_frames_gen * src->GetChannels(); - - size_t samples = srcData.input_frames_used * src->GetChannels(); - if (!samples) - break; //TODO happens? - src->mInBuffer.read(samples); - } - - DWORD resMutex = WaitForSingleObject(src->mMutex, 30000); - if (resMutex != WAIT_OBJECT_0) - { - goto error; - } - - size_t len = output_frames * src->GetChannels(); - float* pSrc = rebuf.data(); - while (len > 0) - { - size_t samples = std::min(len, src->mOutBuffer.peek_write(true)); - src_float_to_short_array(pSrc, src->mOutBuffer.back(), samples); - src->mOutBuffer.write(samples); - len -= samples; - pSrc += samples; - } - - if (!ReleaseMutex(src->mMutex)) - { - goto error; - } - } - Sleep(src->mDeviceLost ? 1000 : 1); - } - - quit: - ret = 0; - error: - if (bThreadComInitialized) - CoUninitialize(); - - _endthreadex(ret); - return ret; - } - - unsigned WINAPI MMAudioDevice::RenderThread(LPVOID ptr) - { - MMAudioDevice* src = (MMAudioDevice*)ptr; - std::vector buffer; - UINT32 bufferFrameCount, numFramesPadding, numFramesAvailable; - BYTE* pData; - SRC_DATA srcData; - unsigned ret = 1; - HRESULT hr = 0; - bool bThreadComInitialized = false; - - memset(&srcData, 0, sizeof(SRC_DATA)); - - //TODO APARTMENTTHREADED instead? - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if ((S_OK != hr) && (S_FALSE != hr) /* already inited */ && (hr != RPC_E_CHANGED_MODE)) - { - goto error; - } - - if (hr != RPC_E_CHANGED_MODE) - bThreadComInitialized = true; - - //Call mmClient->Start() here instead? - - while (!src->mQuit) - { - while (src->mPaused) - { - Sleep(100); - if (src->mQuit) - goto quit; - } - - if (src->mDeviceLost && !src->Reinitialize()) - { - Sleep(1000); - continue; - } - - DWORD resMutex = WaitForSingleObject(src->mMutex, 5000); - if (resMutex != WAIT_OBJECT_0) - { - goto error; - } - - hr = src->mmClient->GetBufferSize(&bufferFrameCount); - if (FAILED(hr)) - goto device_error; - - hr = src->mmClient->GetCurrentPadding(&numFramesPadding); - if (FAILED(hr)) - goto device_error; - - numFramesAvailable = std::min(bufferFrameCount - numFramesPadding, UINT32(src->mInBuffer.size() / src->GetChannels())); - - if (src->mInBuffer.size()) - { - buffer.resize(src->mInBuffer.size()); - size_t read = buffer.size(); - - while (read > 0 && numFramesAvailable > 0) - { - size_t samples = std::min(src->mInBuffer.peek_read(), read); - src_short_to_float_array(src->mInBuffer.front(), - buffer.data(), samples); - - //XXX May get AUDCLNT_E_BUFFER_TOO_LARGE - hr = src->mmRender->GetBuffer(numFramesAvailable, &pData); - if (FAILED(hr)) - goto device_error; - - srcData.data_in = buffer.data(); - srcData.input_frames = samples / src->GetChannels(); - srcData.data_out = (float*)pData; - srcData.output_frames = numFramesAvailable; - srcData.src_ratio = src->mResampleRatio; - - src_process(src->mResampler, &srcData); - - hr = src->mmRender->ReleaseBuffer(srcData.output_frames_gen, 0); - if (FAILED(hr)) - goto device_error; - - read -= srcData.input_frames_used * src->GetChannels(); - src->mInBuffer.read(srcData.input_frames_used * src->GetChannels()); - } - } - // TODO WASAPI seems to stop playing when buffer underrun, so skip this - /*else - { - if (numFramesPadding < src->mDeviceSamplesPerSec / 1000) - { - numFramesAvailable = std::min(bufferFrameCount - numFramesPadding, (src->mDeviceSamplesPerSec / 1000)); - - hr = src->mmRender->GetBuffer(numFramesAvailable, &pData); - if (FAILED(hr)) - goto device_error; - hr = src->mmRender->ReleaseBuffer(numFramesAvailable, AUDCLNT_BUFFERFLAGS_SILENT); - } - }*/ - - device_error: - if (!ReleaseMutex(src->mMutex)) - { - goto error; - } - - if (FAILED(hr)) - { - if (hr == AUDCLNT_E_DEVICE_INVALIDATED) - { - src->mDeviceLost = true; - } - else - goto error; - } - - Sleep(src->mDeviceLost ? 1000 : 10); - } - - quit: - ret = 0; - error: - if (bThreadComInitialized) - CoUninitialize(); - - _endthreadex(ret); - return ret; - } - - uint32_t MMAudioDevice::GetBuffer(int16_t* outBuf, uint32_t outFrames) - { - if (!mQuit && (mThread == INVALID_HANDLE_VALUE || - WaitForSingleObject(mThread, 0) == WAIT_OBJECT_0)) //Thread got killed prematurely - { - mThread = (HANDLE)_beginthreadex(NULL, 0, MMAudioDevice::CaptureThread, this, 0, NULL); - } - - DWORD resMutex = WaitForSingleObject(mMutex, 1000); - if (resMutex != WAIT_OBJECT_0) - { - return 0; - } - - //mSamples += outFrames; - //mTime = GetQPCTime100NS(); - //if (mLastTimeNS == 0) mLastTimeNS = mTime; - //LONGLONG diff = mTime - mLastTimeNS; - //if (diff >= LONGLONG(1e7)) - //{ - // mTimeAdjust = (mSamples / (diff / 1e7)) / mSamplesPerSec; - // //if(mTimeAdjust > 1.0) mTimeAdjust = 1.0; //If game is in 'turbo mode', just return zero samples or...? - // mLastTimeNS = mTime; - // mSamples = 0; - //} - - int samples_to_read = outFrames * mDeviceChannels; - short* pDst = (short*)outBuf; - //assert(samples_to_read <= mOutBuffer.size()); - - while (samples_to_read > 0) - { - int samples = std::min(samples_to_read, (int)mOutBuffer.peek_read()); - if (!samples) - break; - memcpy(pDst, mOutBuffer.front(), samples * sizeof(short)); - - mOutBuffer.read(samples); - pDst += samples; - samples_to_read -= samples; - } - - resMutex = ReleaseMutex(mMutex); - return (outFrames - (samples_to_read / mDeviceChannels)); - } - - uint32_t MMAudioDevice::SetBuffer(int16_t* inBuf, uint32_t inFrames) - { - if (!mQuit && (mThread == INVALID_HANDLE_VALUE || - WaitForSingleObject(mThread, 0) == WAIT_OBJECT_0)) //Thread got killed prematurely - { - mThread = (HANDLE)_beginthreadex(NULL, 0, MMAudioDevice::RenderThread, this, 0, NULL); - } - - DWORD resMutex = WaitForSingleObject(mMutex, 1000); - if (resMutex != WAIT_OBJECT_0) - { - return 0; - } - - size_t nbytes = inFrames * sizeof(short) * GetChannels(); - mInBuffer.write((uint8_t*)inBuf, nbytes); - - if (!ReleaseMutex(mMutex)) - { - } - - return inFrames; - } - - /* - Returns read frame count. -*/ - uint32_t MMAudioDevice::GetMMBuffer() - { - UINT64 devPosition, qpcTimestamp; - LPBYTE captureBuffer; - UINT32 numFramesRead; - DWORD dwFlags = 0; - - if (mDeviceLost) - { - FreeData(); - if (Reinitialize()) - { - Start(); - } - else - { - return 0; - } - } - - UINT32 captureSize = 0; - HRESULT hRes = mmCapture->GetNextPacketSize(&captureSize); - - if (FAILED(hRes)) - { - if (hRes == AUDCLNT_E_DEVICE_INVALIDATED) - { - mDeviceLost = true; - FreeData(); - } - return 0; - } - - if (!captureSize) - return 0; - - if (SUCCEEDED(mmCapture->GetBuffer(&captureBuffer, &numFramesRead, &dwFlags, &devPosition, &qpcTimestamp))) - { - size_t totalLen = numFramesRead * mDeviceChannels; - if (dwFlags & AUDCLNT_BUFFERFLAGS_SILENT) - { - while (totalLen && mInBuffer.peek_write() > 0) - { - size_t len = std::min(totalLen, mInBuffer.peek_write()); - memset(mInBuffer.back(), 0, sizeof(float) * len); - mInBuffer.write(len); - totalLen -= len; - } - } - else - { - mInBuffer.write((uint8_t*)captureBuffer, sizeof(float) * totalLen); - } - - mmCapture->ReleaseBuffer(numFramesRead); - } - - return numFramesRead; - } - - void MMAudioDevice::SetResampling(int samplerate) - { - if (mDeviceSamplesPerSec == samplerate) - { - mResample = false; - return; - } - mSamplesPerSec = samplerate; - if (mAudioDir == AUDIODIR_SOURCE) - mResampleRatio = double(samplerate) / double(mDeviceSamplesPerSec); - else - mResampleRatio = double(mDeviceSamplesPerSec) / double(samplerate); - mResample = true; - ResetBuffers(); - } - - bool MMAudioDevice::AudioInit() - { - QueryPerformanceFrequency(&clockFreq); - return true; - } - - void MMAudioDevice::AudioDevices(std::vector& devices, AudioDir dir) - { - const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); - const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); - IMMDeviceEnumerator* mmEnumerator; - HRESULT err; - - err = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&mmEnumerator); - if (FAILED(err)) - { - Console.WriteLn("AudioDevices: Could not create IMMDeviceEnumerator\n"); - return; - } - - IMMDeviceCollection* collection; - EDataFlow audioDeviceType = (dir == AUDIODIR_SOURCE ? eCapture : eRender); - DWORD flags = DEVICE_STATE_ACTIVE; - //if (!bConnectedOnly) - flags |= DEVICE_STATE_UNPLUGGED; - - err = mmEnumerator->EnumAudioEndpoints(audioDeviceType, flags, &collection); - if (FAILED(err)) - { - Console.WriteLn("AudioDevices: Could not enumerate audio endpoints\n"); - SafeRelease(mmEnumerator); - return; - } - - UINT count; - if (SUCCEEDED(collection->GetCount(&count))) - { - for (UINT i = 0; i < count; i++) - { - IMMDevice* device; - if (SUCCEEDED(collection->Item(i, &device))) - { - const WCHAR* wstrID; - if (SUCCEEDED(device->GetId((LPWSTR*)&wstrID))) - { - IPropertyStore* store; - if (SUCCEEDED(device->OpenPropertyStore(STGM_READ, &store))) - { - PROPVARIANT varName; - - PropVariantInit(&varName); - if (SUCCEEDED(store->GetValue(PKEY_Device_FriendlyName, &varName))) - { - const WCHAR* wstrName = varName.pwszVal; - - AudioDeviceInfo info; - info.strID = wstrID; - info.strName = wstrName; - devices.push_back(info); - } - } - - CoTaskMemFree((LPVOID)wstrID); - } - - SafeRelease(device); - } - } - } - - SafeRelease(collection); - SafeRelease(mmEnumerator); - } - - int MMAudioDevice::Configure(int port, const char* dev_type, void* data) - { - Win32Handles h = *(Win32Handles*)data; - WASAPISettings settings; - settings.port = port; - settings.dev_type = dev_type; - - return (int)DialogBoxParam(h.hInst, - MAKEINTRESOURCE(IDD_DLGWASAPI_USB), - h.hWnd, - (DLGPROC)WASAPIDlgProc, (LPARAM)&settings); - } - - static void RefreshInputAudioList(HWND hW, LRESULT idx, WASAPISettings* settings) - { - settings->sourceDevs.clear(); - - SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_RESETCONTENT, 0, 0); - SendDlgItemMessage(hW, IDC_COMBO2_USB, CB_RESETCONTENT, 0, 0); - - SendDlgItemMessageW(hW, IDC_COMBO1_USB, CB_ADDSTRING, 0, (LPARAM)L"None"); - SendDlgItemMessageW(hW, IDC_COMBO2_USB, CB_ADDSTRING, 0, (LPARAM)L"None"); - - SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_SETCURSEL, 0, 0); - SendDlgItemMessage(hW, IDC_COMBO2_USB, CB_SETCURSEL, 0, 0); - - MMAudioDevice::AudioDevices(settings->sourceDevs, AUDIODIR_SOURCE); - AudioDeviceInfoList::iterator it; - int i = 0; - for (it = settings->sourceDevs.begin(); it != settings->sourceDevs.end(); ++it) - { - SendDlgItemMessageW(hW, IDC_COMBO1_USB, CB_ADDSTRING, 0, (LPARAM)it->strName.c_str()); - SendDlgItemMessageW(hW, IDC_COMBO2_USB, CB_ADDSTRING, 0, (LPARAM)it->strName.c_str()); - - i++; - if (it->strID == settings->selectedDev[0]) - SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_SETCURSEL, i, i); - if (it->strID == settings->selectedDev[1]) - SendDlgItemMessage(hW, IDC_COMBO2_USB, CB_SETCURSEL, i, i); - } - } - - static void RefreshOutputAudioList(HWND hW, LRESULT idx, WASAPISettings* settings) - { - settings->sinkDevs.clear(); - - SendDlgItemMessage(hW, IDC_COMBO3_USB, CB_RESETCONTENT, 0, 0); - SendDlgItemMessageW(hW, IDC_COMBO3_USB, CB_ADDSTRING, 0, (LPARAM)L"None"); - SendDlgItemMessage(hW, IDC_COMBO3_USB, CB_SETCURSEL, 0, 0); - - MMAudioDevice::AudioDevices(settings->sinkDevs, AUDIODIR_SINK); - AudioDeviceInfoList::iterator it; - int i = 0; - for (it = settings->sinkDevs.begin(); it != settings->sinkDevs.end(); ++it) - { - SendDlgItemMessageW(hW, IDC_COMBO3_USB, CB_ADDSTRING, 0, (LPARAM)it->strName.c_str()); - - i++; - if (it->strID == settings->selectedDev[2]) - SendDlgItemMessage(hW, IDC_COMBO3_USB, CB_SETCURSEL, i, i); - } - } - - static BOOL CALLBACK WASAPIDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - WASAPISettings* s; - - switch (uMsg) - { - case WM_CREATE: - SetWindowLongPtr(hW, GWLP_USERDATA, lParam); - break; - case WM_INITDIALOG: - { - s = (WASAPISettings*)lParam; - SetWindowLongPtr(hW, GWLP_USERDATA, lParam); - int buffering = 50; - LoadSetting(s->dev_type, s->port, APINAME, N_BUFFER_LEN_SRC, buffering); - - SendDlgItemMessage(hW, IDC_SLIDER1_USB, TBM_SETRANGEMIN, TRUE, 1); - SendDlgItemMessage(hW, IDC_SLIDER1_USB, TBM_SETRANGEMAX, TRUE, 1000); - SendDlgItemMessage(hW, IDC_SLIDER1_USB, TBM_SETPOS, TRUE, buffering); - SetDlgItemInt(hW, IDC_BUFFER1_USB, buffering, FALSE); - - buffering = 50; - LoadSetting(s->dev_type, s->port, APINAME, N_BUFFER_LEN_SINK, buffering); - - SendDlgItemMessage(hW, IDC_SLIDER2_USB, TBM_SETRANGEMIN, TRUE, 1); - SendDlgItemMessage(hW, IDC_SLIDER2_USB, TBM_SETRANGEMAX, TRUE, 1000); - SendDlgItemMessage(hW, IDC_SLIDER2_USB, TBM_SETPOS, TRUE, buffering); - SetDlgItemInt(hW, IDC_BUFFER2_USB, buffering, FALSE); - - for (int i = 0; i < 2; i++) - { - LoadSetting(s->dev_type, s->port, APINAME, (i ? N_AUDIO_SOURCE1 : N_AUDIO_SOURCE0), s->selectedDev[i]); - } - - LoadSetting(s->dev_type, s->port, APINAME, N_AUDIO_SINK0, s->selectedDev[2]); - - RefreshInputAudioList(hW, -1, s); - RefreshOutputAudioList(hW, -1, s); - return TRUE; - } - case WM_HSCROLL: - if ((HWND)lParam == GetDlgItem(hW, IDC_SLIDER1_USB)) - { - int pos = SendDlgItemMessage(hW, IDC_SLIDER1_USB, TBM_GETPOS, 0, 0); - SetDlgItemInt(hW, IDC_BUFFER1_USB, pos, FALSE); - break; - } - else if ((HWND)lParam == GetDlgItem(hW, IDC_SLIDER2_USB)) - { - int pos = SendDlgItemMessage(hW, IDC_SLIDER2_USB, TBM_GETPOS, 0, 0); - SetDlgItemInt(hW, IDC_BUFFER2_USB, pos, FALSE); - break; - } - break; - - case WM_COMMAND: - switch (HIWORD(wParam)) - { - case EN_CHANGE: - { - int tmp = 0; - switch (LOWORD(wParam)) - { - case IDC_BUFFER1_USB: - CHECKED_SET_MAX_INT(tmp, hW, IDC_BUFFER1_USB, FALSE, 1, 1000); - SendDlgItemMessage(hW, IDC_SLIDER1_USB, TBM_SETPOS, TRUE, tmp); - break; - case IDC_BUFFER2_USB: - CHECKED_SET_MAX_INT(tmp, hW, IDC_BUFFER2_USB, FALSE, 1, 1000); - SendDlgItemMessage(hW, IDC_SLIDER2_USB, TBM_SETPOS, TRUE, tmp); - break; - } - } - break; - case BN_CLICKED: - { - switch (LOWORD(wParam)) - { - case IDOK: - { - int p[3]; - s = (WASAPISettings*)GetWindowLongPtr(hW, GWLP_USERDATA); - INT_PTR res = RESULT_OK; - p[0] = SendDlgItemMessage(hW, IDC_COMBO1_USB, CB_GETCURSEL, 0, 0); - p[1] = SendDlgItemMessage(hW, IDC_COMBO2_USB, CB_GETCURSEL, 0, 0); - p[2] = SendDlgItemMessage(hW, IDC_COMBO3_USB, CB_GETCURSEL, 0, 0); - - for (int i = 0; i < 3; i++) - { - s->selectedDev[i].clear(); - - if (p[i] > 0) - s->selectedDev[i] = ((i < 2 ? s->sourceDevs.begin() : s->sinkDevs.begin()) + p[i] - 1)->strID; - } - - const wchar_t* n[] = {N_AUDIO_SOURCE0, N_AUDIO_SOURCE1, N_AUDIO_SINK0}; - for (int i = 0; i < 3; i++) - { - if (!SaveSetting(s->dev_type, s->port, APINAME, n[i], s->selectedDev[i])) - res = RESULT_FAILED; - } - - if (!SaveSetting(s->dev_type, s->port, APINAME, N_BUFFER_LEN_SRC, (int32_t)SendDlgItemMessage(hW, IDC_SLIDER1_USB, TBM_GETPOS, 0, 0))) - res = RESULT_FAILED; - - if (!SaveSetting(s->dev_type, s->port, APINAME, N_BUFFER_LEN_SINK, (int32_t)SendDlgItemMessage(hW, IDC_SLIDER2_USB, TBM_GETPOS, 0, 0))) - res = RESULT_FAILED; - - EndDialog(hW, res); - return TRUE; - } - case IDCANCEL: - EndDialog(hW, RESULT_CANCELED); - return TRUE; - } - } - break; - } - } - return FALSE; - } - - } // namespace audiodev_wasapi -} // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/audiodev-wasapi.h b/pcsx2/USB/usb-mic/audiodev-wasapi.h deleted file mode 100644 index 981d0738a4..0000000000 --- a/pcsx2/USB/usb-mic/audiodev-wasapi.h +++ /dev/null @@ -1,161 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -// Used OBS as example - -#include "audiodeviceproxy.h" -#include -#include "USB/shared/ringbuffer.h" - -#include -#include - -namespace usb_mic -{ - namespace audiodev_wasapi - { - - static const char* APINAME = "wasapi"; - - class MMAudioDevice : public AudioDevice - { - public: - MMAudioDevice(int port, const char* dev_type, int device, AudioDir dir) - : AudioDevice(port, dev_type, device, dir) - , mmCapture(NULL) - , mmRender(NULL) - , mmClient(NULL) - , mmDevice(NULL) - , mmClock(NULL) - , mmEnumerator(NULL) - , mResampler(NULL) - , mDeviceLost(false) - , mResample(false) - , mFirstSamples(true) - , mSamplesPerSec(48000) - , mResampleRatio(1.0) - , mTimeAdjust(1.0) - , mThread(INVALID_HANDLE_VALUE) - , mQuit(false) - , mPaused(true) - , mLastGetBufferMS(0) - , mBuffering(50) - { - mMutex = CreateMutex(NULL, FALSE, TEXT("ResampledQueueMutex")); - if (!Init()) - throw AudioDeviceError("MMAudioDevice:: device name is empty, skipping"); - if (!Reinitialize()) - throw AudioDeviceError("MMAudioDevice:: WASAPI init failed!"); - } - - ~MMAudioDevice(); - void FreeData(); - bool Init(); - bool Reinitialize(); - void Start(); - void Stop(); - void ResetBuffers(); - //TODO or just return samples count in mOutBuffer? - virtual bool GetFrames(uint32_t* size); - - static unsigned WINAPI CaptureThread(LPVOID ptr); - static unsigned WINAPI RenderThread(LPVOID ptr); - - virtual uint32_t GetBuffer(int16_t* outBuf, uint32_t outFrames); - virtual uint32_t SetBuffer(int16_t* inBuf, uint32_t inFrames); - /* - Returns read frame count. - */ - uint32_t GetMMBuffer(); - virtual void SetResampling(int samplerate); - virtual uint32_t GetChannels() - { - return mDeviceChannels; - } - - virtual bool Compare(AudioDevice* compare) - { - if (compare) - { - MMAudioDevice* src = static_cast(compare); - if (src && mDevID == src->mDevID) - return true; - } - return false; - } - - static const char* TypeName() - { - return APINAME; - } - - static const TCHAR* Name() - { - return TEXT("WASAPI"); - } - - static bool AudioInit(); - - static void AudioDeinit() - { - } - - static void AudioDevices(std::vector& devices, AudioDir dir); - static int Configure(int port, const char* dev_type, void* data); - - private: - IMMDeviceEnumerator* mmEnumerator; - - IMMDevice* mmDevice; - IAudioClient* mmClient; - IAudioCaptureClient* mmCapture; - IAudioRenderClient* mmRender; - IAudioClock* mmClock; - - bool mResample; - bool mFloat; - bool mFirstSamples; //On the first call, empty the buffer to lower latency - UINT mDeviceChannels; - UINT mDeviceSamplesPerSec; - UINT mSamplesPerSec; - UINT mDeviceBitsPerSample; - UINT mDeviceBlockSize; - DWORD mInputChannelMask; - - std::wstring mDevID; - bool mDeviceLost; - std::wstring mDeviceName; - LONGLONG mBuffering; - - SRC_STATE* mResampler; - double mResampleRatio; - // Speed up or slow down audio - double mTimeAdjust; - RingBuffer mInBuffer; - RingBuffer mOutBuffer; - HANDLE mThread; - HANDLE mMutex; - bool mQuit; - bool mPaused; - LONGLONG mLastGetBufferMS; - - LONGLONG mTime = 0; - int mSamples = 0; - LONGLONG mLastTimeMS = 0; - LONGLONG mLastTimeNS = 0; - }; - - } // namespace audiodev_wasapi -} // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/audiodev.h b/pcsx2/USB/usb-mic/audiodev.h index 3f389c88cb..dc16e16e0e 100644 --- a/pcsx2/USB/usb-mic/audiodev.h +++ b/pcsx2/USB/usb-mic/audiodev.h @@ -17,25 +17,12 @@ // Types to shared by platforms and config. dialog. // -#ifndef AUDIODEV_H -#define AUDIODEV_H +#pragma once +#include #include #include -#include - -#define S_AUDIO_SOURCE0 TEXT("Audio source 1") -#define S_AUDIO_SOURCE1 TEXT("Audio source 2") -#define S_AUDIO_SINK0 TEXT("Audio sink 1") -#define S_AUDIO_SINK1 TEXT("Audio sink 2") -#define N_AUDIO_SOURCE0 TEXT("audio_src_0") -#define N_AUDIO_SOURCE1 TEXT("audio_src_1") -#define N_AUDIO_SINK0 TEXT("audio_sink_0") -#define N_AUDIO_SINK1 TEXT("audio_sink_1") -#define S_BUFFER_LEN TEXT("Buffer length") -#define N_BUFFER_LEN TEXT("buffer_len") -#define N_BUFFER_LEN_SRC TEXT("buffer_len_src") -#define N_BUFFER_LEN_SINK TEXT("buffer_len_sink") +#include enum MicMode { @@ -53,46 +40,28 @@ enum AudioDir AUDIODIR_SINK }; -//TODO sufficient for linux too? -struct AudioDeviceInfoA -{ - //int intID; //optional ID - std::string strID; - std::string strName; //gui name -}; - -struct AudioDeviceInfoW -{ - //int intID; //optional ID - std::wstring strID; - std::wstring strName; //gui name -}; - -#if _WIN32 -#define AudioDeviceInfo AudioDeviceInfoW -#else -#define AudioDeviceInfo AudioDeviceInfoA -#endif - class AudioDevice { public: - AudioDevice(int port, const char* dev_type, int device, AudioDir dir) + static constexpr s32 DEFAULT_LATENCY = 100; + static constexpr const char* DEFAULT_LATENCY_STR = "100"; + + AudioDevice(u32 port, AudioDir dir, u32 channels) : mPort(port) - , mDevType(dev_type) - , mDevice(device) , mAudioDir(dir) + , mChannels(channels) { } protected: - int mPort; - const char* mDevType; - int mDevice; + u32 mPort; + s32 mSubDevice; AudioDir mAudioDir; + u32 mChannels; public: - virtual ~AudioDevice() {} + virtual ~AudioDevice() = default; + //get buffer, converted to 16bit int format virtual uint32_t GetBuffer(int16_t* buff, uint32_t len) = 0; virtual uint32_t SetBuffer(int16_t* buff, uint32_t len) = 0; @@ -102,17 +71,16 @@ public: */ virtual bool GetFrames(uint32_t* size) = 0; virtual void SetResampling(int samplerate) = 0; - virtual uint32_t GetChannels() = 0; + uint32_t GetChannels() { return mChannels; } - virtual void Start() {} - virtual void Stop() {} + virtual bool Start() = 0; + virtual void Stop() = 0; // Compare if another instance is using the same device - virtual bool Compare(AudioDevice* compare) = 0; + virtual bool Compare(AudioDevice* compare) const = 0; - //Remember to add to your class - //static const wchar_t* GetName(); + static std::unique_ptr CreateDevice(u32 port, AudioDir dir, u32 channels, std::string devname, s32 latency); + static std::unique_ptr CreateNoopDevice(u32 port, AudioDir dir, u32 channels); + static std::vector> GetInputDeviceList(); + static std::vector> GetOutputDeviceList(); }; - -typedef std::vector AudioDeviceInfoList; -#endif diff --git a/pcsx2/USB/usb-mic/audiodeviceproxy.h b/pcsx2/USB/usb-mic/audiodeviceproxy.h deleted file mode 100644 index 3998048da9..0000000000 --- a/pcsx2/USB/usb-mic/audiodeviceproxy.h +++ /dev/null @@ -1,109 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef AUDIODEVICEPROXY_H -#define AUDIODEVICEPROXY_H -#include -#include -#include -#include -#include -#include -#include "USB/helpers.h" -#include "USB/configuration.h" -#include "USB/deviceproxy.h" -#include "audiodev.h" - -namespace usb_mic -{ - - class AudioDeviceError : public std::runtime_error - { - public: - AudioDeviceError(const char* msg) - : std::runtime_error(msg) - { - } - virtual ~AudioDeviceError() throw() {} - }; - - class AudioDeviceProxyBase : public ProxyBase - { - AudioDeviceProxyBase(const AudioDeviceProxyBase&) = delete; - AudioDeviceProxyBase& operator=(const AudioDeviceProxyBase&) = delete; - - public: - AudioDeviceProxyBase(){}; - AudioDeviceProxyBase(const std::string& name); - virtual AudioDevice* CreateObject(int port, const char* dev_type, int mic, AudioDir dir) const = 0; //Can be generalized? Probably not - virtual void AudioDevices(std::vector& devices, AudioDir) const = 0; - virtual bool AudioInit() = 0; - virtual void AudioDeinit() = 0; - }; - - template - class AudioDeviceProxy : public AudioDeviceProxyBase - { - AudioDeviceProxy(const AudioDeviceProxy&) = delete; - - public: - AudioDeviceProxy() {} - AudioDeviceProxy(const std::string& name) - : AudioDeviceProxyBase(name) - { - } //Why can't it automagically, ugh - ~AudioDeviceProxy() { } - - AudioDevice* CreateObject(int port, const char* dev_type, int mic, AudioDir dir) const - { - try - { - return new T(port, dev_type, mic, dir); - } - catch (AudioDeviceError& err) - { - (void)err; - return nullptr; - } - } - virtual const TCHAR* Name() const - { - return T::Name(); - } - virtual int Configure(int port, const char* dev_type, void* data) - { - return T::Configure(port, dev_type, data); - } - virtual void AudioDevices(std::vector& devices, AudioDir dir) const - { - T::AudioDevices(devices, dir); - } - virtual bool AudioInit() - { - return T::AudioInit(); - } - virtual void AudioDeinit() - { - T::AudioDeinit(); - } - }; - - class RegisterAudioDevice : public RegisterProxy - { - public: - static void Register(); - }; -} // namespace usb_mic -#endif diff --git a/pcsx2/USB/usb-mic/usb-headset.cpp b/pcsx2/USB/usb-mic/usb-headset.cpp index 073232e8ed..6101c622a0 100644 --- a/pcsx2/USB/usb-mic/usb-headset.cpp +++ b/pcsx2/USB/usb-mic/usb-headset.cpp @@ -25,13 +25,14 @@ // Most stuff is based on Qemu 1.7 USB soundcard passthrough code. #include "PrecompiledHeader.h" -#include "USB/qemu-usb/vl.h" +#include "USB/qemu-usb/qusb.h" #include "USB/qemu-usb/desc.h" -#include "USB/shared/inifile_usb.h" -#include - -#include "audio.h" -#include "usb-headset.h" +#include "USB/qemu-usb/USBinternal.h" +#include "USB/usb-mic/audio.h" +#include "USB/usb-mic/usb-headset.h" +#include "USB/usb-mic/audiodev.h" +#include "USB/USB.h" +#include "StateWrapper.h" #define BUFFER_FRAMES 200 @@ -50,9 +51,8 @@ namespace usb_mic typedef struct HeadsetState { USBDevice dev; - AudioDevice* audsrc; - AudioDevice* audsink; - AudioDeviceProxyBase* audsrcproxy; + std::unique_ptr audsrc; + std::unique_ptr audsink; struct freeze { @@ -79,7 +79,7 @@ namespace usb_mic bool mute; uint8_t vol[2]; } mixer; //TODO - } f; //freezable + } f; //freezable std::vector in_buffer; std::vector out_buffer; @@ -88,367 +88,351 @@ namespace usb_mic USBDescDevice desc_dev; } HeadsetState; - std::list HeadsetDevice::ListAPIs() - { - return RegisterAudioDevice::instance().Names(); - } - const TCHAR* HeadsetDevice::LongAPIName(const std::string& name) - { - return RegisterAudioDevice::instance().Proxy(name)->Name(); - } - static const uint8_t headset_dev_descriptor[] = { - /* bLength */ 0x12, //(18) - /* bDescriptorType */ 0x01, //(1) + /* bLength */ 0x12, //(18) + /* bDescriptorType */ 0x01, //(1) /* bcdUSB */ WBVAL(0x0110), //(272) - /* bDeviceClass */ 0x00, //(0) - /* bDeviceSubClass */ 0x00, //(0) - /* bDeviceProtocol */ 0x00, //(0) - /* bMaxPacketSize0 */ 0x40, //(64) + /* bDeviceClass */ 0x00, //(0) + /* bDeviceSubClass */ 0x00, //(0) + /* bDeviceProtocol */ 0x00, //(0) + /* bMaxPacketSize0 */ 0x40, //(64) /* idVendor */ WBVAL(0x046d), //Logitech /* idProduct */ WBVAL(0x0a01), //"USB headset" from usb.ids /* bcdDevice */ WBVAL(0x1012), //(10.12) - /* iManufacturer */ 0x01, //(1) - /* iProduct */ 0x02, //(2) - /* iSerialNumber */ 0x00, //(0) unused - /* bNumConfigurations */ 0x01, //(1) + /* iManufacturer */ 0x01, //(1) + /* iProduct */ 0x02, //(2) + /* iSerialNumber */ 0x00, //(0) unused + /* bNumConfigurations */ 0x01, //(1) }; static const uint8_t headset_config_descriptor[] = { /* Configuration 1 */ - USB_CONFIGURATION_DESC_SIZE, /* bLength */ + USB_CONFIGURATION_DESC_SIZE, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ - WBVAL(318), /* wTotalLength */ - 0x03, /* bNumInterfaces */ - 0x01, /* bConfigurationValue */ - 0x00, /* iConfiguration */ - USB_CONFIG_BUS_POWERED, /* bmAttributes */ - USB_CONFIG_POWER_MA(100), /* bMaxPower */ + WBVAL(318), /* wTotalLength */ + 0x03, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + USB_CONFIG_BUS_POWERED, /* bmAttributes */ + USB_CONFIG_POWER_MA(100), /* bMaxPower */ /* Interface 0, Alternate Setting 0, Audio Control */ - USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ + USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x00, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x00, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ - AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Control Interface */ AUDIO_CONTROL_INTERFACE_DESC_SZ(2), /* bLength : 8+n */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ - WBVAL(0x0100), /* 1.00 */ /* bcdADC */ - WBVAL(0x0075), /* wTotalLength : this + following unit/terminal sizes */ - 0x02, /* bInCollection */ - 0x01, /* baInterfaceNr(0) */ - 0x02, /* baInterfaceNr(1) */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ + WBVAL(0x0100), /* 1.00 */ /* bcdADC */ + WBVAL(0x0075), /* wTotalLength : this + following unit/terminal sizes */ + 0x02, /* bInCollection */ + 0x01, /* baInterfaceNr(0) */ + 0x02, /* baInterfaceNr(1) */ /* Audio Input Terminal */ - AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength : 12 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ - 0x0d, /* bTerminalID */ + AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength : 12 */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ + 0x0d, /* bTerminalID */ WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */ - 0x00, /* bAssocTerminal */ - 0x01, /* bNrChannels */ - WBVAL(AUDIO_CHANNEL_L), /* wChannelConfig */ - 0x00, /* iChannelNames */ - 0x00, /* iTerminal */ + 0x00, /* bAssocTerminal */ + 0x01, /* bNrChannels */ + WBVAL(AUDIO_CHANNEL_L), /* wChannelConfig */ + 0x00, /* iChannelNames */ + 0x00, /* iTerminal */ /* Audio Feature Unit 6 */ AUDIO_FEATURE_UNIT_DESC_SZ(1, 1), /* bLength : f(ch,n) = 7 + (ch+1)*n */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ - 0x06, /* bUnitID */ - 0x0d, /* bSourceID */ - 0x01, /* bControlSize */ - 0x03, /* bmaControls(0) */ /* mute / volume */ - 0x00, /* bmaControls(1) */ - 0x00, /* iFeature */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ + 0x06, /* bUnitID */ + 0x0d, /* bSourceID */ + 0x01, /* bControlSize */ + 0x03, /* bmaControls(0) */ /* mute / volume */ + 0x00, /* bmaControls(1) */ + 0x00, /* iFeature */ /* Audio Input Terminal */ - AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength : 12 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ - 0x0c, /* bTerminalID */ - WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */ - 0x00, /* bAssocTerminal */ - 0x02, /* bNrChannels */ + AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength : 12 */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ + 0x0c, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */ + 0x00, /* bAssocTerminal */ + 0x02, /* bNrChannels */ WBVAL((AUDIO_CHANNEL_L | AUDIO_CHANNEL_R)), /* wChannelConfig */ - 0x00, /* iChannelNames */ - 0x00, /* iTerminal */ + 0x00, /* iChannelNames */ + 0x00, /* iTerminal */ AUDIO_MIXER_UNIT_DESC_SZ(2, 1), //0x0A+p+n //0x0d - AUDIO_INTERFACE_DESCRIPTOR_TYPE, - AUDIO_CONTROL_MIXER_UNIT, - 0x09, /* bUnitID */ - 0x02, /* bNrInPins */ - 0x0c, /* baSourceID( 0) */ - 0x06, /* baSourceID( 1) */ - 0x02, /* bNrChannels */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, AUDIO_CONTROL_MIXER_UNIT, 0x09, /* bUnitID */ + 0x02, /* bNrInPins */ + 0x0c, /* baSourceID( 0) */ + 0x06, /* baSourceID( 1) */ + 0x02, /* bNrChannels */ WBVAL((AUDIO_CHANNEL_L | AUDIO_CHANNEL_R)), /* wChannelConfig */ - 0, /* iChannelNames */ - 0x00, /* bmControls */ - 0, /* iMixer */ + 0, /* iChannelNames */ + 0x00, /* bmControls */ + 0, /* iMixer */ /* Audio Feature Unit 1 */ AUDIO_FEATURE_UNIT_DESC_SZ(2, 1), /* bLength : f(ch,n) = 7 + (ch+1)*n */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ - 0x01, /* bUnitID */ - 0x09, /* bSourceID */ - 0x01, /* bControlSize */ - 0x01, /* bmaControls(0) */ /* mute */ - 0x02, /* bmaControls(1) */ /* volume */ - 0x02, /* bmaControls(2) */ /* volume */ - 0x00, /* iFeature */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ + 0x01, /* bUnitID */ + 0x09, /* bSourceID */ + 0x01, /* bControlSize */ + 0x01, /* bmaControls(0) */ /* mute */ + 0x02, /* bmaControls(1) */ /* volume */ + 0x02, /* bmaControls(2) */ /* volume */ + 0x00, /* iFeature */ /* Audio Output Terminal */ AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength : 9 */ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ - 0x0e, /* bTerminalID */ - WBVAL(AUDIO_TERMINAL_SPEAKER), /* wTerminalType */ - 0x00, /* bAssocTerminal */ - 0x01, /* bSourceID */ - 0x00, /* iTerminal */ + AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ + 0x0e, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_SPEAKER), /* wTerminalType */ + 0x00, /* bAssocTerminal */ + 0x01, /* bSourceID */ + 0x00, /* iTerminal */ /* Audio Input Terminal */ - AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength : 12 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ - 0x0b, /* bTerminalID */ + AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength : 12 */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ + 0x0b, /* bTerminalID */ WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */ - 0x00, /* bAssocTerminal */ - 0x01, /* bNrChannels */ - WBVAL(AUDIO_CHANNEL_L), /* wChannelConfig */ - 0x00, /* iChannelNames */ - 0x00, /* iTerminal */ + 0x00, /* bAssocTerminal */ + 0x01, /* bNrChannels */ + WBVAL(AUDIO_CHANNEL_L), /* wChannelConfig */ + 0x00, /* iChannelNames */ + 0x00, /* iTerminal */ /* Audio Feature Unit 2 */ AUDIO_FEATURE_UNIT_DESC_SZ(1, 1), /* bLength : f(ch,n) = 7 + (ch+1)*n */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ - 0x02, /* bUnitID */ - 0x0b, /* bSourceID */ - 0x01, /* bControlSize */ - 0x03, /* bmaControls(0) */ /* mute, volume */ - 0x00, /* bmaControls(1) */ - 0x00, /* iFeature */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ + 0x02, /* bUnitID */ + 0x0b, /* bSourceID */ + 0x01, /* bControlSize */ + 0x03, /* bmaControls(0) */ /* mute, volume */ + 0x00, /* bmaControls(1) */ + 0x00, /* iFeature */ - AUDIO_MIXER_UNIT_DESC_SZ(1, 1), - AUDIO_INTERFACE_DESCRIPTOR_TYPE, - AUDIO_CONTROL_MIXER_UNIT, - 0x07, /* bUnitID */ - 0x01, /* bNrInPins */ - 0x02, /* baSourceID( 0) */ - 0x01, /* bNrChannels */ + AUDIO_MIXER_UNIT_DESC_SZ(1, 1), AUDIO_INTERFACE_DESCRIPTOR_TYPE, AUDIO_CONTROL_MIXER_UNIT, 0x07, /* bUnitID */ + 0x01, /* bNrInPins */ + 0x02, /* baSourceID( 0) */ + 0x01, /* bNrChannels */ WBVAL(AUDIO_CHANNEL_L), /* wChannelConfig */ - 0, /* iChannelNames */ - 0x00, /* bmControls */ - 0, /* iMixer */ + 0, /* iChannelNames */ + 0x00, /* bmControls */ + 0, /* iMixer */ /* Audio Output Terminal */ - AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength : 9 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ - 0x0a, /* bTerminalID */ + AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength : 9 */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ + 0x0a, /* bTerminalID */ WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */ - 0x00, /* bAssocTerminal */ - 0x07, /* bSourceID */ - 0x00, /* iTerminal */ + 0x00, /* bAssocTerminal */ + 0x07, /* bSourceID */ + 0x00, /* iTerminal */ /* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */ - USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ + USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x01, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x00, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Interface 1, Alternate Setting 1, Audio Streaming - Operational */ - USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ + USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x01, /* bInterfaceNumber */ - 0x01, /* bAlternateSetting */ - 0x01, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Streaming Interface */ AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength : 7 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ - 0x0c, /* bTerminalLink */ - 0x01, /* bDelay */ - WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x0c, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ /* Audio Type I Format */ - AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength : 8 + (n*3) */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength : 8 + (n*3) */ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ - AUDIO_FORMAT_TYPE_I, /* bFormatType */ - 0x02, /* bNrChannels */ - 0x02, /* bSubFrameSize */ - 0x10, /* bBitResolution */ - 0x05, /* bSamFreqType */ - B3VAL(8000), /* tSamFreq 1 */ - B3VAL(11025), /* tSamFreq 2 */ - B3VAL(22050), /* tSamFreq 3 */ - B3VAL(44100), /* tSamFreq 4 */ - B3VAL(48000), /* tSamFreq 5 */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x02, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ /* Endpoint - Standard Descriptor */ - AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - USB_ENDPOINT_OUT(1), /* bEndpointAddress */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_OUT(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */ - WBVAL(0x00c0), /* wMaxPacketSize */ - 0x01, /* bInterval */ - 0x00, /* bRefresh */ - 0x00, /* bSynchAddress */ + WBVAL(0x00c0), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ /* Endpoint - Audio Streaming */ AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength : 7 */ - AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ - 0x01, /* bmAttributes */ - 0x00, /* bLockDelayUnits */ - WBVAL(0x0000), /* wLockDelay */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ /* Interface 1, Alternate Setting 2, Audio Streaming - Operational */ - USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ + USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x01, /* bInterfaceNumber */ - 0x02, /* bAlternateSetting */ - 0x01, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x01, /* bInterfaceNumber */ + 0x02, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Streaming Interface */ AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength : 7 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ - 0x0c, /* bTerminalLink */ - 0x01, /* bDelay */ - WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x0c, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ /* Audio Type I Format */ - AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength : 8 + (n*3) */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength : 8 + (n*3) */ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ - AUDIO_FORMAT_TYPE_I, /* bFormatType */ - 0x01, /* bNrChannels */ - 0x02, /* bSubFrameSize */ - 0x10, /* bBitResolution */ - 0x05, /* bSamFreqType */ - B3VAL(8000), /* tSamFreq 1 */ - B3VAL(11025), /* tSamFreq 2 */ - B3VAL(22050), /* tSamFreq 3 */ - B3VAL(44100), /* tSamFreq 4 */ - B3VAL(48000), /* tSamFreq 5 */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x01, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ /* Endpoint - Standard Descriptor */ - AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - USB_ENDPOINT_OUT(1), /* bEndpointAddress */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_OUT(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */ - WBVAL(0x0060), /* wMaxPacketSize */ - 0x01, /* bInterval */ - 0x00, /* bRefresh */ - 0x00, /* bSynchAddress */ + WBVAL(0x0060), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ /* Endpoint - Audio Streaming */ AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength : 7 */ - AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ - 0x01, /* bmAttributes */ - 0x00, /* bLockDelayUnits */ - WBVAL(0x0000), /* wLockDelay */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ /* Interface 2, Alternate Setting 0 */ - USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ + USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x02, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x00, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x02, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Interface 2, Alternate Setting 1 */ - USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ + USB_INTERFACE_DESC_SIZE, /* bLength : 9 */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x02, /* bInterfaceNumber */ - 0x01, /* bAlternateSetting */ - 0x01, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x02, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Streaming Interface */ AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength : 7 */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ - 0x0a, /* bTerminalLink */ - 0x00, /* bDelay */ - WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x0a, /* bTerminalLink */ + 0x00, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ /* Audio Type I Format */ - AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength : 8+(n*3) */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength : 8+(n*3) */ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ - AUDIO_FORMAT_TYPE_I, /* bFormatType */ - 0x01, /* bNrChannels */ - 0x02, /* bSubFrameSize */ - 0x10, /* bBitResolution */ - 0x05, /* bSamFreqType */ - B3VAL(8000), /* tSamFreq 1 */ - B3VAL(11025), /* tSamFreq 2 */ - B3VAL(22050), /* tSamFreq 3 */ - B3VAL(44100), /* tSamFreq 4 */ - B3VAL(48000), /* tSamFreq 5 */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x01, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ /* Endpoint - Standard Descriptor */ - AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - USB_ENDPOINT_IN(4), /* bEndpointAddress */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_IN(4), /* bEndpointAddress */ USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */ - WBVAL(0x0060), /* wMaxPacketSize */ - 0x01, /* bInterval */ - 0x00, /* bRefresh */ - 0x00, /* bSynchAddress */ + WBVAL(0x0060), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ /* Endpoint - Audio Streaming */ AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength : 7 */ - AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ - 0x01, /* bmAttributes */ - 0x02, /* bLockDelayUnits (PCM samples) */ - WBVAL(0x0001), /* wLockDelay */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x02, /* bLockDelayUnits (PCM samples) */ + WBVAL(0x0001), /* wLockDelay */ /* Terminator */ 0 /* bLength */ }; - static const USBDescStrings desc_strings = { - "", + static const USBDescStrings desc_strings = {"", "Logitech", // Atleast SOCOM II checks this (liblgaud?) - "Logitech USB Headset", - "00000000"}; + "Logitech USB Headset", "00000000"}; static void headset_handle_reset(USBDevice* dev) { @@ -459,17 +443,14 @@ namespace usb_mic /* * Note: we arbitrarily map the volume control range onto -inf..+8 dB */ -#define ATTRIB_ID(cs, attrib, idif) \ - (((cs) << 24) | ((attrib) << 16) | (idif)) +#define ATTRIB_ID(cs, attrib, idif) (((cs) << 24) | ((attrib) << 16) | (idif)) // With current descriptor, if I'm not mistaken, // feature unit 2 (0x0100): headphones // feature unit 5 (0x0600): microphone - static int usb_audio_get_control(HeadsetState* s, uint8_t attrib, - uint16_t cscn, uint16_t idif, - int length, uint8_t* data) + static int usb_audio_get_control(HeadsetState* s, uint8_t attrib, uint16_t cscn, uint16_t idif, int length, uint8_t* data) { uint8_t cs = cscn >> 8; const uint8_t cn = cscn - 1; /* -1 for the non-present master control */ @@ -570,9 +551,10 @@ namespace usb_mic ret = 2; } break; - case ATTRIB_ID(AUDIO_BASS_BOOST_CONTROL, AUDIO_REQUEST_GET_CUR, 0x0100): //??? SOCOM II when in stereo, but there is no bass control defined in descriptor... - //if (cn < 2) { //asks with cn == 2, meaning both channels? -1 is 'master' - data[0] = 0; //bool + case ATTRIB_ID(AUDIO_BASS_BOOST_CONTROL, AUDIO_REQUEST_GET_CUR, + 0x0100): //??? SOCOM II when in stereo, but there is no bass control defined in descriptor... + //if (cn < 2) { //asks with cn == 2, meaning both channels? -1 is 'master' + data[0] = 0; //bool ret = 1; //} break; @@ -581,9 +563,7 @@ namespace usb_mic return ret; } - static int usb_audio_set_control(HeadsetState* s, uint8_t attrib, - uint16_t cscn, uint16_t idif, - int length, uint8_t* data) + static int usb_audio_set_control(HeadsetState* s, uint8_t attrib, uint16_t cscn, uint16_t idif, int length, uint8_t* data) { uint8_t cs = cscn >> 8; const uint8_t cn = cscn - 1; /* -1 for the non-present master control */ @@ -655,9 +635,7 @@ namespace usb_mic return ret; } - static int usb_audio_ep_control(HeadsetState* s, uint8_t attrib, - uint16_t cscn, uint16_t ep, - int length, uint8_t* data) + static int usb_audio_ep_control(HeadsetState* s, uint8_t attrib, uint16_t cscn, uint16_t ep, int length, uint8_t* data) { uint8_t cs = cscn >> 8; [[maybe_unused]] const uint8_t cn = cscn - 1; /* -1 for the non-present master control */ @@ -701,10 +679,9 @@ namespace usb_mic return ret; } - static void headset_handle_control(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + static void headset_handle_control(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) { - HeadsetState* s = (HeadsetState*)dev; + HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev); int ret = 0; @@ -723,8 +700,7 @@ namespace usb_mic case ClassInterfaceRequest | AUDIO_REQUEST_GET_MIN: case ClassInterfaceRequest | AUDIO_REQUEST_GET_MAX: case ClassInterfaceRequest | AUDIO_REQUEST_GET_RES: - ret = usb_audio_get_control(s, request & 0xff, value, index, - length, data); + ret = usb_audio_get_control(s, request & 0xff, value, index, length, data); if (ret < 0) { //if (s->debug) { @@ -739,8 +715,7 @@ namespace usb_mic case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_MIN: case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_MAX: case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_RES: - ret = usb_audio_set_control(s, request & 0xff, value, index, - length, data); + ret = usb_audio_set_control(s, request & 0xff, value, index, length, data); if (ret < 0) { //if (s->debug) { @@ -758,8 +733,7 @@ namespace usb_mic case ClassEndpointOutRequest | AUDIO_REQUEST_SET_MIN: case ClassEndpointOutRequest | AUDIO_REQUEST_SET_MAX: case ClassEndpointOutRequest | AUDIO_REQUEST_SET_RES: - ret = usb_audio_ep_control(s, request & 0xff, value, index, - length, data); + ret = usb_audio_ep_control(s, request & 0xff, value, index, length, data); if (ret < 0) goto fail; break; @@ -779,7 +753,7 @@ namespace usb_mic static void headset_handle_data(USBDevice* dev, USBPacket* p) { - HeadsetState* s = (HeadsetState*)dev; + HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev); int ret = USB_RET_STALL; uint8_t devep = p->ep->nr; @@ -808,7 +782,7 @@ namespace usb_mic if (s->audsrc->GetFrames(&frames)) { - frames = MIN(frames, maxFrames); + frames = std::min(frames, maxFrames); s->in_buffer.resize(frames * inChns); frames = s->audsrc->GetBuffer(s->in_buffer.data(), frames); } @@ -913,7 +887,7 @@ namespace usb_mic static void headset_handle_destroy(USBDevice* dev) { - HeadsetState* s = (HeadsetState*)dev; + HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev); if (file) fclose(file); file = NULL; @@ -923,40 +897,33 @@ namespace usb_mic if (s->audsrc) { s->audsrc->Stop(); - delete s->audsrc; - s->audsrc = NULL; + s->audsrc.reset(); s->in_buffer.clear(); } if (s->audsink) { s->audsink->Stop(); - delete s->audsink; - s->audsink = NULL; + s->audsink.reset(); s->out_buffer.clear(); } - s->audsrcproxy->AudioDeinit(); delete s; } static int headset_handle_open(USBDevice* dev) { - HeadsetState* s = (HeadsetState*)dev; + HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev); if (s) { - if (s->audsrc) - s->audsrc->Start(); - if (s->audsink) - s->audsink->Start(); } return 0; } static void headset_handle_close(USBDevice* dev) { - HeadsetState* s = (HeadsetState*)dev; + HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev); if (s) { if (s->audsrc) @@ -967,40 +934,25 @@ namespace usb_mic } } - USBDevice* HeadsetDevice::CreateDevice(int port) + USBDevice* HeadsetDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { - std::string api; -#ifdef _WIN32 - std::wstring tmp; - if (!LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp)) - return nullptr; - api = wstr_to_str(tmp); -#else - if (!LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, api)) - return nullptr; -#endif - return HeadsetDevice::CreateDevice(port, api); - } + HeadsetState* s = new HeadsetState(); - USBDevice* HeadsetDevice::CreateDevice(int port, const std::string& api) - { - HeadsetState* s; - AudioDeviceInfo info; + std::string input_devname(USB::GetConfigString(si, port, TypeName(), "input_device")); + std::string output_devname(USB::GetConfigString(si, port, TypeName(), "output_device")); + const s32 input_latency = USB::GetConfigInt(si, port, TypeName(), "input_latency", AudioDevice::DEFAULT_LATENCY); + const s32 output_latency = USB::GetConfigInt(si, port, TypeName(), "output_latency", AudioDevice::DEFAULT_LATENCY); - s = new HeadsetState(); + if (!input_devname.empty()) + s->audsrc = AudioDevice::CreateDevice(port, AUDIODIR_SOURCE, 1, std::move(input_devname), input_latency); + else + s->audsrc = AudioDevice::CreateNoopDevice(port, AUDIODIR_SOURCE, 1); - s->audsrcproxy = RegisterAudioDevice::instance().Proxy(api); - if (!s->audsrcproxy) - { - Console.WriteLn("headset: Invalid audio API: '%s'\n", api.c_str()); - delete s; - return NULL; - } + if (!output_devname.empty()) + s->audsink = AudioDevice::CreateDevice(port, AUDIODIR_SINK, 2, std::move(output_devname), output_latency); + else + s->audsink = AudioDevice::CreateNoopDevice(port, AUDIODIR_SINK, 2); - s->audsrcproxy->AudioInit(); - - s->audsrc = s->audsrcproxy->CreateObject(port, TypeName(), 0, AUDIODIR_SOURCE); - s->audsink = s->audsrcproxy->CreateObject(port, TypeName(), 0, AUDIODIR_SINK); s->f.mode = MIC_MODE_SINGLE; if (!s->audsrc || !s->audsink) @@ -1009,6 +961,9 @@ namespace usb_mic s->in_buffer.reserve(BUFFER_FRAMES * s->audsrc->GetChannels()); s->out_buffer.reserve(BUFFER_FRAMES * s->audsink->GetChannels()); + s->audsrc->Start(); + s->audsink->Start(); + s->desc.full = &s->desc_dev; s->desc.str = desc_strings; if (usb_desc_parse_dev(headset_dev_descriptor, sizeof(headset_dev_descriptor), s->desc, s->desc_dev) < 0) @@ -1022,60 +977,82 @@ namespace usb_mic s->dev.klass.handle_control = headset_handle_control; s->dev.klass.handle_data = headset_handle_data; s->dev.klass.unrealize = headset_handle_destroy; - s->dev.klass.open = headset_handle_open; - s->dev.klass.close = headset_handle_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = desc_strings[2]; // set defaults s->f.out.vol[0] = 240; /* 0 dB */ s->f.out.vol[1] = 240; /* 0 dB */ - s->f.in.vol = 240; /* 0 dB */ + s->f.in.vol = 240; /* 0 dB */ s->f.out.srate = 48000; s->f.in.srate = 48000; usb_desc_init(&s->dev); usb_ep_init(&s->dev); - headset_handle_reset((USBDevice*)s); + headset_handle_reset(&s->dev); - return (USBDevice*)s; + return &s->dev; fail: - headset_handle_destroy((USBDevice*)s); - return NULL; + headset_handle_destroy(&s->dev); + return nullptr; } - int HeadsetDevice::Configure(int port, const std::string& api, void* data) + const char* HeadsetDevice::TypeName() const { - auto proxy = RegisterAudioDevice::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; + return "headset"; } - int HeadsetDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* HeadsetDevice::Name() const { - HeadsetState* s = (HeadsetState*)dev; - if (!s) - return 0; - switch (mode) + return "Logitech USB Headset"; + } + + bool HeadsetDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev); + if (!sw.DoMarker("HeadsetDevice")) + return false; + + sw.Do(&s->f.intf); + sw.Do(&s->f.mode); + sw.Do(&s->f.out.mute); + sw.DoPODArray(s->f.out.vol, std::size(s->f.out.vol)); + sw.Do(&s->f.out.srate); + sw.Do(&s->f.in.mute); + sw.Do(&s->f.in.vol); + sw.Do(&s->f.in.srate); + sw.Do(&s->f.mixer.mute); + sw.DoPODArray(s->f.mixer.vol, std::size(s->f.mixer.vol)); + + if (sw.IsReading() && !sw.HasError()) { - case FreezeAction::Load: - s->f = *(HeadsetState::freeze*)data; - if (s->audsrc) - s->audsrc->SetResampling(s->f.in.srate); - if (s->audsink) - s->audsink->SetResampling(s->f.out.srate); - return sizeof(HeadsetState::freeze); - case FreezeAction::Save: - *(HeadsetState::freeze*)data = s->f; - return sizeof(HeadsetState::freeze); - case FreezeAction::Size: - return sizeof(HeadsetState::freeze); - default: - break; + if (s->audsrc) + s->audsrc->SetResampling(s->f.in.srate); + if (s->audsink) + s->audsink->SetResampling(s->f.out.srate); } - return 0; + + return !sw.HasError(); } + void HeadsetDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const + { + // TODO: Update device + } + + gsl::span HeadsetDevice::Settings(u32 subtype) const + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::StringList, "input_device_name", "Input Device", "Selects the device to read audio from.", "", nullptr, + nullptr, nullptr, nullptr, nullptr, &AudioDevice::GetInputDeviceList}, + {SettingInfo::Type::StringList, "output_device_name", "Output Device", "Selects the device to output audio to.", "", nullptr, + nullptr, nullptr, nullptr, nullptr, &AudioDevice::GetOutputDeviceList}, + {SettingInfo::Type::Integer, "input_latency", "Input Latency", "Specifies the latency to the host input device.", AudioDevice::DEFAULT_LATENCY_STR, "0", + "1000", "1", "%dms", nullptr, nullptr, 1.0f}, + {SettingInfo::Type::Integer, "output_latency", "Output Latency", "Specifies the latency to the host output device.", AudioDevice::DEFAULT_LATENCY_STR, "0", + "1000", "1", "%dms", nullptr, nullptr, 1.0f}, + }; + return info; + } } // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/usb-headset.h b/pcsx2/USB/usb-mic/usb-headset.h index 310ae5e8df..73deea5384 100644 --- a/pcsx2/USB/usb-mic/usb-headset.h +++ b/pcsx2/USB/usb-mic/usb-headset.h @@ -14,33 +14,19 @@ */ #include "USB/deviceproxy.h" -#include "audiodeviceproxy.h" namespace usb_mic { - - class HeadsetDevice + class HeadsetDevice final : public DeviceProxy { public: - virtual ~HeadsetDevice() {} - static USBDevice* CreateDevice(int port); - static USBDevice* CreateDevice(int port, const std::string& api); - static const char* TypeName() - { - return "headset"; - } - static const TCHAR* Name() - { - return TEXT("Logitech USB Headset"); - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* TypeName() const override; + const char* Name() const override; + + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override; + gsl::span Settings(u32 subtype) const override; }; } // namespace usb_mic diff --git a/pcsx2/USB/usb-mic/usb-mic-logitech.cpp b/pcsx2/USB/usb-mic/usb-mic-logitech.cpp index 1b8eff2b6f..eb90498369 100644 --- a/pcsx2/USB/usb-mic/usb-mic-logitech.cpp +++ b/pcsx2/USB/usb-mic/usb-mic-logitech.cpp @@ -17,11 +17,10 @@ #include "usb-mic-singstar.h" #include "audio.h" #include "USB/qemu-usb/desc.h" -#include "USB/shared/inifile_usb.h" +#include "USB/qemu-usb/USBinternal.h" namespace usb_mic { - static const uint8_t logitech_mic_dev_descriptor[] = { /* bLength */ 0x12, //(18) /* bDescriptorType */ 0x01, //(1) @@ -232,32 +231,21 @@ namespace usb_mic }; //Minified state - typedef struct SINGSTARMICMINIState + struct SINGSTARMICMINIState { USBDevice dev; USBDesc desc; USBDescDevice desc_dev; - } SINGSTARMICMINIState; + }; - USBDevice* LogitechMicDevice::CreateDevice(int port) + USBDevice* LogitechMicDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { - std::string api; -#ifdef _WIN32 - std::wstring tmp; - if (!LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp)) - return nullptr; - api = wstr_to_str(tmp); -#else - if (!LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, api)) - return nullptr; -#endif - - USBDevice* dev = SingstarDevice::CreateDevice(port, api); + USBDevice* dev = SingstarDevice::CreateDevice(si, port, subtype, false, LogitechMicDevice::TypeName()); if (!dev) return nullptr; - SINGSTARMICMINIState* s = (SINGSTARMICMINIState*)dev; + SINGSTARMICMINIState* s = USB_CONTAINER_OF(dev, SINGSTARMICMINIState, dev); s->desc = {}; s->desc_dev = {}; diff --git a/pcsx2/USB/usb-mic/usb-mic-singstar.cpp b/pcsx2/USB/usb-mic/usb-mic-singstar.cpp index c6ac877fdf..d54571539d 100644 --- a/pcsx2/USB/usb-mic/usb-mic-singstar.cpp +++ b/pcsx2/USB/usb-mic/usb-mic-singstar.cpp @@ -25,16 +25,19 @@ // Most stuff is based on Qemu 1.7 USB soundcard passthrough code. #include "PrecompiledHeader.h" -#include "USB/qemu-usb/vl.h" +#include "USB/qemu-usb/qusb.h" #include "USB/qemu-usb/desc.h" -#include "usb-mic-singstar.h" -#include "USB/shared/inifile_usb.h" -#include +#include "USB/qemu-usb/USBinternal.h" +#include "USB/usb-mic/usb-mic-singstar.h" +#include "USB/usb-mic/audiodev.h" +#include "USB/usb-mic/audio.h" +#include "USB/USB.h" +#include "Host.h" +#include "StateWrapper.h" +#include "fmt/format.h" static FILE* file = NULL; -#include "audio.h" - #define BUFFER_FRAMES 200 /* @@ -58,18 +61,17 @@ namespace usb_mic enum usb_audio_altset : int8_t { ALTSET_OFF = 0x00, /* No endpoint */ - ALTSET_ON = 0x01, /* Single endpoint */ + ALTSET_ON = 0x01, /* Single endpoint */ }; - typedef struct SINGSTARMICState + struct SINGSTARMICState { USBDevice dev; USBDesc desc; USBDescDevice desc_dev; - AudioDevice* audsrc[2]; - AudioDeviceProxyBase* audsrcproxy; + std::unique_ptr audsrc[2]; struct freeze { @@ -81,13 +83,13 @@ namespace usb_mic bool mute; uint8_t vol[2]; uint32_t srate[2]; //TODO can it have different rates? - } f; //freezable + } f; //freezable /* properties */ uint32_t debug; std::vector buffer[2]; //uint8_t fifo[2][200]; //on-chip 400byte fifo - } SINGSTARMICState; + }; static const USBDescStrings desc_strings = { "", @@ -98,203 +100,203 @@ namespace usb_mic /* descriptor dumped from a real singstar MIC adapter */ static const uint8_t singstar_mic_dev_descriptor[] = { - /* bLength */ 0x12, //(18) - /* bDescriptorType */ 0x01, //(1) + /* bLength */ 0x12, //(18) + /* bDescriptorType */ 0x01, //(1) /* bcdUSB */ WBVAL(0x0110), //(272) - /* bDeviceClass */ 0x00, //(0) - /* bDeviceSubClass */ 0x00, //(0) - /* bDeviceProtocol */ 0x00, //(0) - /* bMaxPacketSize0 */ 0x08, //(8) + /* bDeviceClass */ 0x00, //(0) + /* bDeviceSubClass */ 0x00, //(0) + /* bDeviceProtocol */ 0x00, //(0) + /* bMaxPacketSize0 */ 0x08, //(8) /* idVendor */ WBVAL(0x1415), //(5141) /* idProduct */ WBVAL(0x0000), //(0) /* bcdDevice */ WBVAL(0x0001), //(1) - /* iManufacturer */ 0x01, //(1) - /* iProduct */ 0x02, //(2) - /* iSerialNumber */ 0x00, //(0) unused - /* bNumConfigurations */ 0x01, //(1) + /* iManufacturer */ 0x01, //(1) + /* iProduct */ 0x02, //(2) + /* iSerialNumber */ 0x00, //(0) unused + /* bNumConfigurations */ 0x01, //(1) }; static const uint8_t singstar_mic_config_descriptor[] = { /* Configuration 1 */ - 0x09, /* bLength */ + 0x09, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ - WBVAL(0x00b1), /* wTotalLength */ - 0x02, /* bNumInterfaces */ - 0x01, /* bConfigurationValue */ - 0x00, /* iConfiguration */ - USB_CONFIG_BUS_POWERED, /* bmAttributes */ - USB_CONFIG_POWER_MA(90), /* bMaxPower */ + WBVAL(0x00b1), /* wTotalLength */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + USB_CONFIG_BUS_POWERED, /* bmAttributes */ + USB_CONFIG_POWER_MA(90), /* bMaxPower */ /* Interface 0, Alternate Setting 0, Audio Control */ - USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x00, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x00, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ - AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ + AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Control Interface */ AUDIO_CONTROL_INTERFACE_DESC_SZ(1), /* bLength */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ - WBVAL(0x0100), /* 1.00 */ /* bcdADC */ - WBVAL(0x0028), /* wTotalLength */ - 0x01, /* bInCollection */ - 0x01, /* baInterfaceNr */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ + WBVAL(0x0100), /* 1.00 */ /* bcdADC */ + WBVAL(0x0028), /* wTotalLength */ + 0x01, /* bInCollection */ + 0x01, /* baInterfaceNr */ /* Audio Input Terminal */ - AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ - 0x01, /* bTerminalID */ - WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */ - 0x02, /* bAssocTerminal */ - 0x02, /* bNrChannels */ + AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ + 0x01, /* bTerminalID */ + WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */ + 0x02, /* bAssocTerminal */ + 0x02, /* bNrChannels */ WBVAL(AUDIO_CHANNEL_L | AUDIO_CHANNEL_R), /* wChannelConfig */ - 0x00, /* iChannelNames */ - 0x00, /* iTerminal */ + 0x00, /* iChannelNames */ + 0x00, /* iTerminal */ /* Audio Output Terminal */ - AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ - 0x02, /* bTerminalID */ + AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ + 0x02, /* bTerminalID */ WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */ - 0x01, /* bAssocTerminal */ - 0x03, /* bSourceID */ - 0x00, /* iTerminal */ + 0x01, /* bAssocTerminal */ + 0x03, /* bSourceID */ + 0x00, /* iTerminal */ /* Audio Feature Unit */ AUDIO_FEATURE_UNIT_DESC_SZ(2, 1), /* bLength */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ - 0x03, /* bUnitID */ - 0x01, /* bSourceID */ - 0x01, /* bControlSize */ - 0x01, /* bmaControls(0) */ - 0x02, /* bmaControls(1) */ - 0x02, /* bmaControls(2) */ - 0x00, /* iTerminal */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ + 0x03, /* bUnitID */ + 0x01, /* bSourceID */ + 0x01, /* bControlSize */ + 0x01, /* bmaControls(0) */ + 0x02, /* bmaControls(1) */ + 0x02, /* bmaControls(2) */ + 0x00, /* iTerminal */ /* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */ - USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x01, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x00, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x00, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Interface 1, Alternate Setting 1, Audio Streaming - Operational */ - USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x01, /* bInterfaceNumber */ - 0x01, /* bAlternateSetting */ - 0x01, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x01, /* bInterfaceNumber */ + 0x01, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Streaming Interface */ AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ - 0x02, /* bTerminalLink */ - 0x01, /* bDelay */ - WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x02, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ /* Audio Type I Format */ - AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ - AUDIO_FORMAT_TYPE_I, /* bFormatType */ - 0x01, /* bNrChannels */ - 0x02, /* bSubFrameSize */ - 0x10, /* bBitResolution */ - 0x05, /* bSamFreqType */ - B3VAL(8000), /* tSamFreq 1 */ - B3VAL(11025), /* tSamFreq 2 */ - B3VAL(22050), /* tSamFreq 3 */ - B3VAL(44100), /* tSamFreq 4 */ - B3VAL(48000), /* tSamFreq 5 */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x01, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ /* Endpoint - Standard Descriptor */ - AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - USB_ENDPOINT_IN(1), /* bEndpointAddress */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_IN(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */ - WBVAL(0x0064), /* wMaxPacketSize */ - 0x01, /* bInterval */ - 0x00, /* bRefresh */ - 0x00, /* bSynchAddress */ + WBVAL(0x0064), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ /* Endpoint - Audio Streaming */ AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */ - AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ - 0x01, /* bmAttributes */ - 0x00, /* bLockDelayUnits */ - WBVAL(0x0000), /* wLockDelay */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ /* Interface 1, Alternate Setting 2, Audio Streaming - ? */ - USB_INTERFACE_DESC_SIZE, /* bLength */ + USB_INTERFACE_DESC_SIZE, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - 0x01, /* bInterfaceNumber */ - 0x02, /* bAlternateSetting */ - 0x01, /* bNumEndpoints */ - USB_CLASS_AUDIO, /* bInterfaceClass */ + 0x01, /* bInterfaceNumber */ + 0x02, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + USB_CLASS_AUDIO, /* bInterfaceClass */ AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ - AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ - 0x00, /* iInterface */ + AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ + 0x00, /* iInterface */ /* Audio Streaming Interface */ AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */ - AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ - 0x02, /* bTerminalLink */ - 0x01, /* bDelay */ - WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ + 0x02, /* bTerminalLink */ + 0x01, /* bDelay */ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */ /* Audio Type I Format */ - AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */ + AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ - AUDIO_FORMAT_TYPE_I, /* bFormatType */ - 0x02, /* bNrChannels */ - 0x02, /* bSubFrameSize */ - 0x10, /* bBitResolution */ - 0x05, /* bSamFreqType */ - B3VAL(8000), /* tSamFreq 1 */ - B3VAL(11025), /* tSamFreq 2 */ - B3VAL(22050), /* tSamFreq 3 */ - B3VAL(44100), /* tSamFreq 4 */ - B3VAL(48000), /* tSamFreq 5 */ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ + 0x02, /* bNrChannels */ + 0x02, /* bSubFrameSize */ + 0x10, /* bBitResolution */ + 0x05, /* bSamFreqType */ + B3VAL(8000), /* tSamFreq 1 */ + B3VAL(11025), /* tSamFreq 2 */ + B3VAL(22050), /* tSamFreq 3 */ + B3VAL(44100), /* tSamFreq 4 */ + B3VAL(48000), /* tSamFreq 5 */ /* Endpoint - Standard Descriptor */ - AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ - USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - USB_ENDPOINT_IN(1), /* bEndpointAddress */ + AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + USB_ENDPOINT_IN(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */ - WBVAL(0x00c8), /* wMaxPacketSize */ - 0x01, /* bInterval */ - 0x00, /* bRefresh */ - 0x00, /* bSynchAddress */ + WBVAL(0x00c8), /* wMaxPacketSize */ + 0x01, /* bInterval */ + 0x00, /* bRefresh */ + 0x00, /* bSynchAddress */ /* Endpoint - Audio Streaming */ AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */ - AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ - AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ - 0x01, /* bmAttributes */ - 0x00, /* bLockDelayUnits */ - WBVAL(0x0000), /* wLockDelay */ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ + 0x01, /* bmAttributes */ + 0x00, /* bLockDelayUnits */ + WBVAL(0x0000), /* wLockDelay */ /* Terminator */ 0 /* bLength */ @@ -310,14 +312,11 @@ namespace usb_mic /* * Note: we arbitrarily map the volume control range onto -inf..+8 dB */ -#define ATTRIB_ID(cs, attrib, idif) \ - (((cs) << 24) | ((attrib) << 16) | (idif)) +#define ATTRIB_ID(cs, attrib, idif) (((cs) << 24) | ((attrib) << 16) | (idif)) //0x0300 - feature bUnitID 0x03 - static int usb_audio_get_control(SINGSTARMICState* s, uint8_t attrib, - uint16_t cscn, uint16_t idif, - int length, uint8_t* data) + static int usb_audio_get_control(SINGSTARMICState* s, uint8_t attrib, uint16_t cscn, uint16_t idif, int length, uint8_t* data) { uint8_t cs = cscn >> 8; uint8_t cn = cscn - 1; /* -1 for the non-present master control */ @@ -375,9 +374,7 @@ namespace usb_mic return ret; } - static int usb_audio_set_control(SINGSTARMICState* s, uint8_t attrib, - uint16_t cscn, uint16_t idif, - int length, uint8_t* data) + static int usb_audio_set_control(SINGSTARMICState* s, uint8_t attrib, uint16_t cscn, uint16_t idif, int length, uint8_t* data) { uint8_t cs = cscn >> 8; uint8_t cn = cscn - 1; /* -1 for the non-present master control */ @@ -424,9 +421,7 @@ namespace usb_mic return ret; } - static int usb_audio_ep_control(SINGSTARMICState* s, uint8_t attrib, - uint16_t cscn, uint16_t ep, - int length, uint8_t* data) + static int usb_audio_ep_control(SINGSTARMICState* s, uint8_t attrib, uint16_t cscn, uint16_t ep, int length, uint8_t* data) { uint8_t cs = cscn >> 8; uint8_t cn = cscn - 1; /* -1 for the non-present master control */ @@ -452,7 +447,6 @@ namespace usb_mic if (s->audsrc[1]) s->audsrc[1]->SetResampling(s->f.srate[1]); - } else if (cn < 2) { @@ -474,10 +468,9 @@ namespace usb_mic return ret; } - static void singstar_mic_set_interface(USBDevice* dev, int intf, - int alt_old, int alt_new) + static void singstar_mic_set_interface(USBDevice* dev, int intf, int alt_old, int alt_new) { - SINGSTARMICState* s = (SINGSTARMICState*)dev; + SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev); s->f.intf = alt_new; #if defined(_DEBUG) /* close previous debug audio output file */ @@ -489,10 +482,9 @@ namespace usb_mic #endif } - static void singstar_mic_handle_control(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + static void singstar_mic_handle_control(USBDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) { - SINGSTARMICState* s = (SINGSTARMICState*)dev; + SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev); int ret = 0; @@ -511,8 +503,7 @@ namespace usb_mic case ClassInterfaceRequest | AUDIO_REQUEST_GET_MIN: case ClassInterfaceRequest | AUDIO_REQUEST_GET_MAX: case ClassInterfaceRequest | AUDIO_REQUEST_GET_RES: - ret = usb_audio_get_control(s, request & 0xff, value, index, - length, data); + ret = usb_audio_get_control(s, request & 0xff, value, index, length, data); if (ret < 0) { //if (s->debug) { @@ -527,8 +518,7 @@ namespace usb_mic case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_MIN: case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_MAX: case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_RES: - ret = usb_audio_set_control(s, request & 0xff, value, index, - length, data); + ret = usb_audio_set_control(s, request & 0xff, value, index, length, data); if (ret < 0) { //if (s->debug) { @@ -546,8 +536,7 @@ namespace usb_mic case ClassEndpointOutRequest | AUDIO_REQUEST_SET_MIN: case ClassEndpointOutRequest | AUDIO_REQUEST_SET_MAX: case ClassEndpointOutRequest | AUDIO_REQUEST_SET_RES: - ret = usb_audio_ep_control(s, request & 0xff, value, index, - length, data); + ret = usb_audio_ep_control(s, request & 0xff, value, index, length, data); if (ret < 0) goto fail; break; @@ -567,7 +556,7 @@ namespace usb_mic static void singstar_mic_handle_data(USBDevice* dev, USBPacket* p) { - SINGSTARMICState* s = (SINGSTARMICState*)dev; + SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev); int ret = 0; uint8_t devep = p->ep->nr; @@ -606,10 +595,9 @@ namespace usb_mic for (int i = 0; i < 2; i++) { frames = max_frames; - if (s->audsrc[i] && - s->audsrc[i]->GetFrames(&frames)) + if (s->audsrc[i] && s->audsrc[i]->GetFrames(&frames)) { - frames = MIN(max_frames, frames); //max 50 frames usually + frames = std::min(max_frames, frames); //max 50 frames usually out_frames[i] = s->audsrc[i]->GetBuffer(s->buffer[i].data(), frames); } } @@ -669,7 +657,7 @@ namespace usb_mic { uint32_t cn1 = s->audsrc[0]->GetChannels(); uint32_t cn2 = s->audsrc[1]->GetChannels(); - uint32_t minLen = MIN(out_frames[0], out_frames[1]); + uint32_t minLen = std::min(out_frames[0], out_frames[1]); src1 = s->buffer[0].data(); src2 = s->buffer[1].data(); @@ -721,7 +709,7 @@ namespace usb_mic static void singstar_mic_handle_destroy(USBDevice* dev) { - SINGSTARMICState* s = (SINGSTARMICState*)dev; + SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev); if (file) fclose(file); file = NULL; @@ -733,81 +721,53 @@ namespace usb_mic if (s->audsrc[i]) { s->audsrc[i]->Stop(); - delete s->audsrc[i]; - s->audsrc[i] = NULL; + s->audsrc[i].reset(); s->buffer[i].clear(); } } - s->audsrcproxy->AudioDeinit(); + delete s; } - static int singstar_mic_handle_open(USBDevice* dev) + USBDevice* SingstarDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { - SINGSTARMICState* s = (SINGSTARMICState*)dev; - if (s) - { - for (int i = 0; i < 2; i++) - if (s->audsrc[i]) - s->audsrc[i]->Start(); - } - return 0; + return CreateDevice(si, port, subtype, true, SingstarDevice::TypeName()); } - static void singstar_mic_handle_close(USBDevice* dev) + USBDevice* SingstarDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype, bool dual_mic, const char* devtype) const { - SINGSTARMICState* s = (SINGSTARMICState*)dev; - if (s) + SINGSTARMICState* s = new SINGSTARMICState(); + + if (dual_mic) { - for (int i = 0; i < 2; i++) - if (s->audsrc[i]) - s->audsrc[i]->Stop(); + std::string dev0(USB::GetConfigString(si, port, devtype, "player1_device_name")); + std::string dev1(USB::GetConfigString(si, port, devtype, "player2_device_name")); + const s32 latency = USB::GetConfigInt(si, port, devtype, "input_latency", AudioDevice::DEFAULT_LATENCY); + + if (!dev0.empty()) + s->audsrc[0] = AudioDevice::CreateDevice(port, AUDIODIR_SOURCE, 1, std::move(dev0), latency); + if (!dev1.empty()) + s->audsrc[1] = AudioDevice::CreateDevice(port, AUDIODIR_SOURCE, 1, std::move(dev1), latency); } - } - - //USBDevice *singstar_mic_init(int port, TSTDSTRING *devs) - USBDevice* SingstarDevice::CreateDevice(int port) - { - std::string api; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, SingstarDevice::TypeName(), N_DEVICE_API, tmp); - api = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, SingstarDevice::TypeName(), N_DEVICE_API, api); -#endif - return SingstarDevice::CreateDevice(port, api); - } - USBDevice* SingstarDevice::CreateDevice(int port, const std::string& api) - { - SINGSTARMICState* s; - AudioDeviceInfo info; - - s = new SINGSTARMICState(); - - s->audsrcproxy = RegisterAudioDevice::instance().Proxy(api); - if (!s->audsrcproxy) + else { - Console.WriteLn("singstar: Invalid audio API: '%s'\n", api.c_str()); - delete s; - return NULL; + std::string dev0(USB::GetConfigString(si, port, devtype, "input_device_name")); + const s32 latency0 = USB::GetConfigInt(si, port, devtype, "input_latency", AudioDevice::DEFAULT_LATENCY); + if (!dev0.empty()) + s->audsrc[0] = AudioDevice::CreateDevice(port, AUDIODIR_SOURCE, 1, std::move(dev0), latency0); } - s->audsrcproxy->AudioInit(); - - s->audsrc[0] = s->audsrcproxy->CreateObject(port, TypeName(), 0, AUDIODIR_SOURCE); - s->audsrc[1] = s->audsrcproxy->CreateObject(port, TypeName(), 1, AUDIODIR_SOURCE); - if (!s->audsrc[0] && !s->audsrc[1]) + { + Host::AddOSDMessage("USB-Mic: Neither player 1 nor 2 is connected.", Host::OSD_ERROR_DURATION); goto fail; + } - if (s->audsrc[0] && s->audsrc[1] && s->audsrc[0]->Compare(s->audsrc[1])) + if (s->audsrc[0] && s->audsrc[1] && s->audsrc[0]->Compare(s->audsrc[1].get())) { s->f.mode = MIC_MODE_SHARED; // And don't capture the same source twice - s->audsrc[1]->Stop(); - delete s->audsrc[1]; - s->audsrc[1] = nullptr; + s->audsrc[1].reset(); } else if (!s->audsrc[0] || !s->audsrc[1]) s->f.mode = MIC_MODE_SINGLE; @@ -815,8 +775,17 @@ namespace usb_mic s->f.mode = MIC_MODE_SEPARATE; for (int i = 0; i < 2; i++) + { if (s->audsrc[i]) + { s->buffer[i].resize(BUFFER_FRAMES * s->audsrc[i]->GetChannels()); + if (!s->audsrc[i]->Start()) + { + Host::AddOSDMessage(fmt::format("USB-Mic: Failed to start player {} audio stream.", i + 1), Host::OSD_ERROR_DURATION); + goto fail; + } + } + } s->desc.full = &s->desc_dev; s->desc.str = desc_strings; @@ -832,8 +801,6 @@ namespace usb_mic s->dev.klass.handle_data = singstar_mic_handle_data; s->dev.klass.set_interface = singstar_mic_set_interface; s->dev.klass.unrealize = singstar_mic_handle_destroy; - s->dev.klass.open = singstar_mic_handle_open; - s->dev.klass.close = singstar_mic_handle_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = desc_strings[2]; @@ -845,46 +812,131 @@ namespace usb_mic usb_desc_init(&s->dev); usb_ep_init(&s->dev); - singstar_mic_handle_reset((USBDevice*)s); + singstar_mic_handle_reset(&s->dev); - return (USBDevice*)s; + return &s->dev; fail: - singstar_mic_handle_destroy((USBDevice*)s); - return NULL; + singstar_mic_handle_destroy(&s->dev); + return nullptr; } - int SingstarDevice::Configure(int port, const std::string& api, void* data) + const char* SingstarDevice::Name() const { - auto proxy = RegisterAudioDevice::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; + return "Singstar"; } - int SingstarDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* SingstarDevice::TypeName() const { - SINGSTARMICState* s = (SINGSTARMICState*)dev; - if (!s) - return 0; - switch (mode) + return "singstar"; + } + + bool SingstarDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev); + if (!sw.DoMarker("SINGSTARMICState")) + return false; + + sw.Do(&s->f.intf); + sw.Do(&s->f.mode); + sw.Do(&s->f.altset); + sw.Do(&s->f.mute); + sw.DoPODArray(&s->f.vol, std::size(s->f.vol)); + sw.DoPODArray(s->f.srate, std::size(s->f.srate)); + + if (sw.IsReading() && !sw.HasError()) { - case FreezeAction::Load: - s->f = *(SINGSTARMICState::freeze*)data; - if (s->audsrc[0]) - s->audsrc[0]->SetResampling(s->f.srate[0]); - if (s->audsrc[1]) - s->audsrc[1]->SetResampling(s->f.srate[1]); - return sizeof(SINGSTARMICState::freeze); - case FreezeAction::Save: - *(SINGSTARMICState::freeze*)data = s->f; - return sizeof(SINGSTARMICState::freeze); - case FreezeAction::Size: - return sizeof(SINGSTARMICState::freeze); - default: - break; + for (u32 i = 0; i < 2; i++) + { + if (s->audsrc[i]) + s->audsrc[i]->SetResampling(s->f.srate[i]); + } } - return 0; + + return !sw.HasError(); } + void SingstarDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const + { + // TODO: Reload devices. + } + + gsl::span SingstarDevice::Settings(u32 subtype) const + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::StringList, "player1_device_name", "Player 1 Device", "Selects the input for the first player.", "", + nullptr, nullptr, nullptr, nullptr, nullptr, &AudioDevice::GetInputDeviceList}, + {SettingInfo::Type::StringList, "player2_device_name", "Player 2 Device", "Selects the input for the second player.", "", + nullptr, nullptr, nullptr, nullptr, nullptr, &AudioDevice::GetInputDeviceList}, + {SettingInfo::Type::Integer, "input_latency", "Input Latency", "Specifies the latency to the host input device.", + AudioDevice::DEFAULT_LATENCY_STR, "0", "1000", "1", "%dms", nullptr, nullptr, 1.0f}, + }; + return info; + } + + const char* LogitechMicDevice::TypeName() const + { + return "logitech_usbmic"; + } + + const char* LogitechMicDevice::Name() const + { + return "Logitech USB Mic"; + } + + gsl::span LogitechMicDevice::Settings(u32 subtype) const + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::StringList, "input_device_name", "Input Device", "Selects the device to read audio from.", "", nullptr, + nullptr, nullptr, nullptr, nullptr, &AudioDevice::GetInputDeviceList}, + {SettingInfo::Type::Integer, "input_latency", "Input Latency", "Specifies the latency to the host input device.", + AudioDevice::DEFAULT_LATENCY_STR, "0", "1000", "1", "%dms", nullptr, nullptr, 1.0f}, + }; + return info; + } } // namespace usb_mic + +#include "USB/usb-mic/audiodev-noop.h" + +std::unique_ptr AudioDevice::CreateNoopDevice(u32 port, AudioDir dir, u32 channels) +{ + return std::make_unique(port, dir, channels); +} + +#ifdef SPU2X_CUBEB +#include "USB/usb-mic/audiodev-cubeb.h" + +std::unique_ptr AudioDevice::CreateDevice(u32 port, AudioDir dir, u32 channels, std::string devname, s32 latency) +{ + return std::make_unique(port, dir, channels, std::move(devname), latency); +} + +std::vector> AudioDevice::GetInputDeviceList() +{ + return usb_mic::audiodev_cubeb::CubebAudioDevice::GetDeviceList(true); +} + +std::vector> AudioDevice::GetOutputDeviceList() +{ + return usb_mic::audiodev_cubeb::CubebAudioDevice::GetDeviceList(false); +} + +#else + +std::unique_ptr AudioDevice::CreateDevice(u32 port, AudioDir dir, u32 channels, std::string devname, s32 latency) +{ + Console.Warning("Cubeb is unavailable, creating a noop audio device."); + return CreateNoopDevice(port, dir, channels); +} + +std::vector AudioDevice::GetInputDeviceList() +{ + return {}; +} + +std::vector AudioDevice::GetOutputDeviceList() +{ + return {}; +} + +#endif \ No newline at end of file diff --git a/pcsx2/USB/usb-mic/usb-mic-singstar.h b/pcsx2/USB/usb-mic/usb-mic-singstar.h index 986ca72407..3a3664af95 100644 --- a/pcsx2/USB/usb-mic/usb-mic-singstar.h +++ b/pcsx2/USB/usb-mic/usb-mic-singstar.h @@ -13,62 +13,30 @@ * If not, see . */ -#ifndef USBMICSINGSTAR_H -#define USBMICSINGSTAR_H +#pragma once #include "USB/deviceproxy.h" -#include "audiodeviceproxy.h" - -struct USBDevice; +#include "USB/usb-mic/audiodev.h" namespace usb_mic { - class SingstarDevice + class SingstarDevice : public DeviceProxy { public: - virtual ~SingstarDevice() {} - static USBDevice* CreateDevice(int port); - static USBDevice* CreateDevice(int port, const std::string& api); - static const TCHAR* Name() - { - return TEXT("Singstar"); - } - static const char* TypeName() - { - return "singstar"; - } - static std::list ListAPIs() - { - return RegisterAudioDevice::instance().Names(); - } - static const TCHAR* LongAPIName(const std::string& name) - { - auto proxy = RegisterAudioDevice::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype, bool dual_mic, const char* devtype) const; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* Name() const override; + const char* TypeName() const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override; + gsl::span Settings(u32 subtype) const override; }; - class LogitechMicDevice : public SingstarDevice + class LogitechMicDevice final : public SingstarDevice { public: - virtual ~LogitechMicDevice() {} - static USBDevice* CreateDevice(int port); - static const char* TypeName() - { - return "logitech_usbmic"; - } - static const TCHAR* Name() - { - return TEXT("Logitech USB Mic"); - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* TypeName() const override; + const char* Name() const override; + gsl::span Settings(u32 subtype) const override; }; - } // namespace usb_mic -#endif diff --git a/pcsx2/USB/usb-msd/usb-msd-gtk.cpp b/pcsx2/USB/usb-msd/usb-msd-gtk.cpp deleted file mode 100644 index 171359db37..0000000000 --- a/pcsx2/USB/usb-msd/usb-msd-gtk.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "usb-msd.h" -#include "USB/linux/ini.h" -#include "USB/configuration.h" -#include "USB/gtk.h" -#include "common/Console.h" - -namespace usb_msd -{ - - static void entryChanged(GtkWidget* widget, gpointer data) - { -#ifndef NDEBUG - const gchar* text = gtk_entry_get_text(GTK_ENTRY(widget)); - Console.Warning("Entry text:%s\n", text); -#endif - } - - static void fileChooser(GtkWidget* widget, gpointer data) - { - GtkWidget *dialog, *entry = NULL; - - entry = (GtkWidget*)data; - dialog = gtk_file_chooser_dialog_new("Open File", - NULL, - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - - //XXX check access? Dialog seems to default to "Recently used" etc. - //Or set to empty string anyway? Then it seems to default to some sort of "working dir" - if (access(gtk_entry_get_text(GTK_ENTRY(entry)), F_OK) == 0) - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), gtk_entry_get_text(GTK_ENTRY(entry))); - - if (entry && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - char* filename; - - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - Console.Warning("%s\n", filename); - gtk_entry_set_text(GTK_ENTRY(entry), filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); - } - - int MsdDevice::Configure(int port, const std::string& api, void* data) - { - GtkWidget *ro_frame, *ro_label, *rs_hbox, *vbox; - - GtkWidget* dlg = gtk_dialog_new_with_buttons( - "Mass Storage Settings", GTK_WINDOW(data), GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE); - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - - ro_frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(dlg_area_box), ro_frame, TRUE, FALSE, 5); - - ro_label = gtk_label_new("Select USB image:"); - gtk_frame_set_label_widget(GTK_FRAME(ro_frame), ro_label); - gtk_label_set_use_markup(GTK_LABEL(ro_label), TRUE); - - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ro_frame), vbox); - - rs_hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), rs_hbox, FALSE, TRUE, 0); - - GtkWidget* entry = gtk_entry_new(); - gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_PATH); //TODO max length - - std::string var; - if (LoadSetting(TypeName(), port, APINAME, N_CONFIG_PATH, var)) - gtk_entry_set_text(GTK_ENTRY(entry), var.c_str()); - - g_signal_connect(entry, "changed", G_CALLBACK(entryChanged), NULL); - - GtkWidget* button = gtk_button_new_with_label("Browse"); - gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_icon_name("gtk-open", GTK_ICON_SIZE_BUTTON)); - g_signal_connect(button, "clicked", G_CALLBACK(fileChooser), entry); - - gtk_box_pack_start(GTK_BOX(rs_hbox), entry, TRUE, TRUE, 5); - gtk_box_pack_start(GTK_BOX(rs_hbox), button, FALSE, FALSE, 5); - - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - std::string path = gtk_entry_get_text(GTK_ENTRY(entry)); - gtk_widget_destroy(dlg); - - // Wait for all gtk events to be consumed ... - while (gtk_events_pending()) - gtk_main_iteration_do(FALSE); - - if (result == GTK_RESPONSE_OK) - { - if (SaveSetting(TypeName(), port, APINAME, N_CONFIG_PATH, path)) - return RESULT_OK; - else - return RESULT_FAILED; - } - - return RESULT_CANCELED; - } - -} // namespace usb_msd diff --git a/pcsx2/USB/usb-msd/usb-msd-win32.cpp b/pcsx2/USB/usb-msd/usb-msd-win32.cpp deleted file mode 100644 index 39e7e5647c..0000000000 --- a/pcsx2/USB/usb-msd/usb-msd-win32.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" - -#include "common/RedtapeWindows.h" - -#include - -#include "usb-msd.h" -#include "USB/Win32/Config_usb.h" -#include "USB/Win32/resource_usb.h" - -namespace usb_msd -{ - - static OPENFILENAMEW ofn; - BOOL CALLBACK MsdDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - int port; - static wchar_t buff[4096] = {0}; - - switch (uMsg) - { - case WM_INITDIALOG: - { - memset(buff, 0, sizeof(buff)); - port = (int)lParam; - SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam); - - std::wstring var; - if (LoadSetting(MsdDevice::TypeName(), port, APINAME, N_CONFIG_PATH, var)) - wcsncpy_s(buff, sizeof(buff), var.c_str(), countof(buff)); - SetWindowTextW(GetDlgItem(hW, IDC_EDIT1_USB), buff); - return TRUE; - } - case WM_CREATE: - SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam); - break; - case WM_COMMAND: - - if (HIWORD(wParam) == BN_CLICKED) - { - switch (LOWORD(wParam)) - { - case IDC_BUTTON1_USB: - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hW; - ofn.lpstrTitle = L"USB image file"; - ofn.lpstrFile = buff; - ofn.nMaxFile = countof(buff); - ofn.lpstrFilter = L"All\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - - if (GetOpenFileName(&ofn)) - { - SetWindowText(GetDlgItem(hW, IDC_EDIT1_USB), ofn.lpstrFile); - } - break; - case IDOK: - { - INT_PTR res = RESULT_OK; - GetWindowTextW(GetDlgItem(hW, IDC_EDIT1_USB), buff, countof(buff)); - port = (int)GetWindowLongPtr(hW, GWLP_USERDATA); - if (!SaveSetting(MsdDevice::TypeName(), port, APINAME, N_CONFIG_PATH, buff)) - res = RESULT_FAILED; - //strcpy_s(conf.usb_img, ofn.lpstrFile); - EndDialog(hW, res); - return TRUE; - } - case IDCANCEL: - EndDialog(hW, FALSE); - return TRUE; - } - } - } - return FALSE; - } - - int MsdDevice::Configure(int port, const std::string& api, void* data) - { - Win32Handles handles = *(Win32Handles*)data; - return DialogBoxParam(handles.hInst, - MAKEINTRESOURCE(IDD_DLGMSD_USB), - handles.hWnd, - (DLGPROC)MsdDlgProc, port); - } - -} // namespace usb_msd diff --git a/pcsx2/USB/usb-msd/usb-msd.cpp b/pcsx2/USB/usb-msd/usb-msd.cpp index 110248e8bd..61007b424f 100644 --- a/pcsx2/USB/usb-msd/usb-msd.cpp +++ b/pcsx2/USB/usb-msd/usb-msd.cpp @@ -8,12 +8,17 @@ */ #include "PrecompiledHeader.h" -#include -#include -#include -#include "USB/qemu-usb/vl.h" +#include +#include +#include +#include "USB/qemu-usb/qusb.h" #include "USB/qemu-usb/desc.h" -#include "usb-msd.h" +#include "USB/qemu-usb/USBinternal.h" +#include "USB/usb-msd/usb-msd.h" +#include "USB/USB.h" +#include "common/FileSystem.h" +#include "Host.h" +#include "StateWrapper.h" #define le32_to_cpu(x) (x) #define cpu_to_le32(x) (x) @@ -48,10 +53,10 @@ namespace usb_msd enum USBMSDMode : int8_t { - USB_MSDM_CBW, /* Command Block. */ + USB_MSDM_CBW, /* Command Block. */ USB_MSDM_DATAOUT, /* Tranfer data to device. */ - USB_MSDM_DATAIN, /* Transfer data from device. */ - USB_MSDM_CSW /* Command Status. */ + USB_MSDM_DATAIN, /* Transfer data from device. */ + USB_MSDM_CSW /* Command Status. */ }; typedef struct ReqState @@ -75,17 +80,18 @@ namespace usb_msd uint32_t file_op_tag; // read from file or buf int32_t result; - uint32_t off; //buffer offset + uint32_t off; //buffer offset uint8_t buf[4096]; //random length right now uint8_t sense_buf[18]; uint8_t last_cmd; ReqState req; //TODO how to detect if image is different - uint32_t hash; - } f; //freezable + uint64_t mtime; + } f = {}; //freezable - FILE* file; + FILE* file = 0; + int64_t file_size = 0; //char fn[MAX_PATH+1]; //TODO Could use with open/close, //but error recovery currently can't deal with file suddenly //becoming not accessible @@ -97,8 +103,8 @@ namespace usb_msd } MSDState; static const uint8_t qemu_msd_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ 0x10, 0x00, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ @@ -114,24 +120,24 @@ namespace usb_msd 0x01, /* u8 iManufacturer; */ 0x02, /* u8 iProduct; */ 0x03, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ + 0x01 /* u8 bNumConfigurations; */ }; static const uint8_t qemu_msd_config_descriptor[] = { /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ 0x20, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ - 0x00, /* u8 MaxPower; */ + 0x00, /* u8 MaxPower; */ /* one interface */ 0x09, /* u8 if_bLength; */ @@ -145,20 +151,20 @@ namespace usb_msd 0x00, /* u8 if_iInterface; */ /* Bulk-In endpoint */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x00, /* u8 ep_bInterval; */ + 0x00, /* u8 ep_bInterval; */ /* Bulk-Out endpoint */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ - 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ 0x00, 0x02, /* u16 ep_wMaxPacketSize; */ - 0x00 /* u8 ep_bInterval; */ + 0x00 /* u8 ep_bInterval; */ }; enum @@ -381,11 +387,11 @@ namespace usb_msd NO_SENSE, 0x00, 0x00}; /* LUN not ready, Manual intervention required */ - [[maybe_unused]]const struct SCSISense sense_code_LUN_NOT_READY = { + [[maybe_unused]] const struct SCSISense sense_code_LUN_NOT_READY = { NOT_READY, 0x04, 0x03}; /* LUN not ready, Medium not present */ - [[maybe_unused]]const struct SCSISense sense_code_NO_MEDIUM = { + [[maybe_unused]] const struct SCSISense sense_code_NO_MEDIUM = { NOT_READY, 0x3a, 0x00}; const struct SCSISense sense_code_UNKNOWN_ERROR = { @@ -411,47 +417,25 @@ namespace usb_msd // .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 //}; - static int64_t get_file_size(FILE* file) - { - int fd; - -#if defined(_WIN32) - struct _stat64 buf; - fd = _fileno(file); - if (_fstat64(fd, &buf) != 0) - return -1; - return buf.st_size; -#elif defined(__GNUC__) - struct stat64 buf; - fd = fileno(file); - if (fstat64(fd, &buf) != 0) - return -1; - return buf.st_size; -#else -#error Unknown platform -#endif - } - static void usb_msd_handle_reset(USBDevice* dev) { - MSDState* s = (MSDState*)dev; + MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev); s->f.mode = USB_MSDM_CBW; } #ifndef bswap32 -#define bswap32(x) ( \ - (((x) >> 24) & 0xff) | \ - (((x) >> 8) & 0xff00) | \ +#define bswap32(x) ( \ + (((x) >> 24) & 0xff) | \ + (((x) >> 8) & 0xff00) | \ (((x) << 8) & 0xff0000) | \ (((x) << 24) & 0xff000000)) #define bswap16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) #endif - static void set_sense(void* opaque, SCSISense sense) + static void set_sense(MSDState* s, SCSISense sense) { - MSDState* s = (MSDState*)opaque; memset(s->f.sense_buf, 0, sizeof(s->f.sense_buf)); //SENSE request s->f.sense_buf[0] = 0x70 | 0x80; //0x70 - current sense, 0x80 - set Valid bit @@ -463,8 +447,8 @@ namespace usb_msd //s->f.sense_buf[5] = 0x00; //s->f.sense_buf[6] = 0x00; //LSB s->f.sense_buf[7] = sense.asc ? 0x0a : 0x00; //Additional sense length (10 bytes if any) - s->f.sense_buf[12] = sense.asc; //Additional sense code - s->f.sense_buf[13] = sense.ascq; //Additional sense code qualifier + s->f.sense_buf[12] = sense.asc; //Additional sense code + s->f.sense_buf[13] = sense.ascq; //Additional sense code qualifier } static void usb_msd_send_status(MSDState* s, USBPacket* p) @@ -472,7 +456,7 @@ namespace usb_msd size_t len; assert(s->f.csw.sig == cpu_to_le32(0x53425355)); - len = MIN(sizeof(s->f.csw), p->iov.size); + len = std::min(sizeof(s->f.csw), p->iov.size); usb_packet_copy(p, &s->f.csw, len); memset(&s->f.csw, 0, sizeof(s->f.csw)); } @@ -604,10 +588,8 @@ namespace usb_msd usb_msd_command_complete(s, s->f.result); } - static void send_command(void* opaque, struct usb_msd_cbw* cbw) + static void send_command(MSDState* s, struct usb_msd_cbw* cbw) { - MSDState* s = (MSDState*)opaque; - int64_t lba; uint32_t xfer_len; s->f.last_cmd = cbw->cmd[0]; @@ -627,29 +609,27 @@ namespace usb_msd break; case REQUEST_SENSE: //device shall keep old sense data memcpy(s->f.buf, s->f.sense_buf, - /* XXX the UFI device shall return only the number of bytes requested, as is */ - cbw->cmd[4] < sizeof(s->f.sense_buf) ? (size_t)cbw->cmd[4] : sizeof(s->f.sense_buf)); + /* XXX the UFI device shall return only the number of bytes requested, as is */ + cbw->cmd[4] < sizeof(s->f.sense_buf) ? (size_t)cbw->cmd[4] : sizeof(s->f.sense_buf)); break; case INQUIRY: memset(s->f.buf, 0, sizeof(s->f.buf)); - s->f.buf[0] = 0; //SCSI Peripheral Device Type: 0x0 - direct access device, 0x1f - unknown/no device + s->f.buf[0] = 0; //SCSI Peripheral Device Type: 0x0 - direct access device, 0x1f - unknown/no device s->f.buf[1] = 1 << 7; //removable - s->f.buf[3] = 1; //UFI response data format + s->f.buf[3] = 1; //UFI response data format //inq data len can be zero - strncpy((char*)&s->f.buf[8], "QEMU", 8); //8 bytes vendor + strncpy((char*)&s->f.buf[8], "QEMU", 8); //8 bytes vendor strncpy((char*)&s->f.buf[16], "USB Drive", 16); //16 bytes product - strncpy((char*)&s->f.buf[32], "1.00", 4); //4 bytes product revision + strncpy((char*)&s->f.buf[32], "1.00", 4); //4 bytes product revision break; case READ_CAPACITY_10: - int64_t fsize, lbas; + int64_t lbas; uint32_t *last_lba, *blk_len; memset(s->f.buf, 0, sizeof(s->f.buf)); - fsize = get_file_size(s->file); - - if (fsize == -1) //TODO + if (s->file_size == 0) //TODO { s->f.result = COMMAND_FAILED; set_sense(s, SENSE_CODE(UNKNOWN_ERROR)); @@ -661,7 +641,7 @@ namespace usb_msd //right? *blk_len = LBA_BLOCK_SIZE; //descriptor is currently max 64 bytes for bulk though - lbas = fsize / LBA_BLOCK_SIZE; + lbas = s->file_size / LBA_BLOCK_SIZE; if (lbas > 0xFFFFFFFF) { s->f.result = COMMAND_FAILED; @@ -691,12 +671,11 @@ namespace usb_msd if (xfer_len == 0) // nothing to do break; - if (fseeko64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET)) + if (FileSystem::FSeek64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET) != 0) { s->f.result = COMMAND_FAILED; //TODO use errno - int64_t fsize = get_file_size(s->file); - if ((lba + xfer_len) * LBA_BLOCK_SIZE > fsize) + if ((lba + xfer_len) * LBA_BLOCK_SIZE > s->file_size) set_sense(s, SENSE_CODE(OUT_OF_RANGE)); else set_sense(s, SENSE_CODE(NO_SEEK_COMPLETE)); @@ -725,12 +704,11 @@ namespace usb_msd if (xfer_len == 0) //nothing to do break; - if (fseeko64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET)) + if (FileSystem::FSeek64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET) != 0) { s->f.result = COMMAND_FAILED; //TODO use errno - int64_t fsize = get_file_size(s->file); - if ((lba + xfer_len) * LBA_BLOCK_SIZE > fsize) + if ((lba + xfer_len) * LBA_BLOCK_SIZE > s->file_size) set_sense(s, SENSE_CODE(OUT_OF_RANGE)); else set_sense(s, SENSE_CODE(NO_SEEK_COMPLETE)); @@ -748,9 +726,9 @@ namespace usb_msd } static void usb_msd_handle_control(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + int index, int length, uint8_t* data) { - MSDState* s = (MSDState*)dev; + MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev); int ret = 0; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); @@ -779,7 +757,7 @@ namespace usb_msd static void usb_msd_cancel_io(USBDevice* dev, USBPacket* p) { - MSDState* s = (MSDState*)(dev); + MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev); assert(s->packet == p); s->packet = NULL; @@ -792,7 +770,7 @@ namespace usb_msd static void usb_msd_handle_data(USBDevice* dev, USBPacket* p) { - MSDState* s = (MSDState*)dev; + MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev); struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; @@ -820,7 +798,7 @@ namespace usb_msd if (le32_to_cpu(cbw.sig) != 0x43425355) { Console.Warning("usb-msd: Bad signature %08x\n", - le32_to_cpu(cbw.sig)); + le32_to_cpu(cbw.sig)); goto fail; } if (cbw.lun != 0) @@ -980,7 +958,7 @@ namespace usb_msd static void usb_msd_handle_destroy(USBDevice* dev) { - MSDState* s = (MSDState*)dev; + MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev); if (s && s->file) { fclose(s->file); @@ -989,31 +967,23 @@ namespace usb_msd delete s; } - USBDevice* MsdDevice::CreateDevice(int port) + USBDevice* MsdDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { MSDState* s = new MSDState(); - //CONFIGVARIANT varApi(N_DEVICE_API, CONFIG_TYPE_CHAR); - //LoadSetting(port, DEVICENAME, varApi); - std::string api = *MsdDevice::ListAPIs().begin(); - - TSTDSTRING var; - - if (!LoadSetting(TypeName(), port, api, N_CONFIG_PATH, var)) + std::string path(USB::GetConfigString(si, port, TypeName(), "ImagePath")); + if (path.empty() || !(s->file = FileSystem::OpenCFile(path.c_str(), "r+b"))) { - Console.Warning("usb-msd: Could not load settings\n"); - delete s; - return NULL; - } - - s->file = wfopen(var.c_str(), TEXT("r+b")); - if (!s->file) - { - Console.WriteLn("usb-msd: Could not open image file '%s'\n", var.c_str()); + Host::AddOSDMessage(fmt::format("usb-msd: Could not open image file '{}'", path), Host::OSD_ERROR_DURATION); goto fail; } - s->f.hash = 0; + FILESYSTEM_STAT_DATA sd; + if (!FileSystem::StatFile(s->file, &sd)) + goto fail; + + s->file_size = sd.Size; + s->f.mtime = sd.ModificationTime; s->f.last_cmd = -1; s->dev.speed = USB_SPEED_FULL; @@ -1036,53 +1006,60 @@ namespace usb_msd usb_desc_init(&s->dev); usb_ep_init(&s->dev); - usb_msd_handle_reset((USBDevice*)s); - return (USBDevice*)s; + usb_msd_handle_reset(&s->dev); + return &s->dev; fail: - usb_msd_handle_destroy((USBDevice*)s); - return NULL; + usb_msd_handle_destroy(&s->dev); + return nullptr; } - const char* MsdDevice::TypeName() + const char* MsdDevice::TypeName() const { - return "msd"; + return "Msd"; } - int MsdDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* MsdDevice::Name() const { - MSDState* s = (MSDState*)dev; - MSDState::freeze* tmp; + return "Mass Storage Device"; + } - if (!s) - return 0; - switch (mode) + bool MsdDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev); + + // use mtime to check when the image has been changed... definitely far from ideal, + // but hashing the file every time we save state is kinda slow. and this isn't a + // heavily used feature... + FILESYSTEM_STAT_DATA sd; + if (s->file && FileSystem::StatFile(s->file, &sd)) + s->f.mtime = static_cast(sd.ModificationTime); + + const u64 old_mtime = s->f.mtime; + sw.DoPOD(&s->f); + + // resetting port to try to avoid possible data corruption + if (sw.IsReading() && old_mtime != s->f.mtime) { - case FreezeAction::Load: - //if (s->f.req) free (s->f.req); - - tmp = (MSDState::freeze*)data; - s->f = *tmp; - //ReqState *req = (ReqState *)((char*)data + sizeof(MSDState::freeze)); - //s->f.req = qemu_mallocz (sizeof(ReqState)); - //*s->f.req = *req; - - //TODO resetting port to try to avoid possible data corruption - //if (s->f.mode == USB_MSDM_DATAOUT) - usb_reattach(dev->port); - return sizeof(MSDState::freeze); // + sizeof(ReqState); - - case FreezeAction::Save: - tmp = (MSDState::freeze*)data; - *tmp = s->f; - return sizeof(MSDState::freeze); - - case FreezeAction::Size: - return sizeof(MSDState::freeze); // + sizeof(ReqState); - default: - break; + Host::AddOSDMessage("Modification time to USB mass storage image changed, reattaching.", + Host::OSD_ERROR_DURATION); + usb_reattach(dev->port); } - return 0; + + return !sw.HasError(); + } + + void MsdDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const + { + // TODO: Handle changes to path. + } + + gsl::span MsdDevice::Settings(u32 subtype) const + { + static constexpr const SettingInfo settings[] = { + {SettingInfo::Type::Path, "ImagePath", "Image Path", "Sets the path to image which will back the virtual mass storage device."}, + }; + return settings; } } // namespace usb_msd diff --git a/pcsx2/USB/usb-msd/usb-msd.h b/pcsx2/USB/usb-msd/usb-msd.h index a32200589b..5331846fa4 100644 --- a/pcsx2/USB/usb-msd/usb-msd.h +++ b/pcsx2/USB/usb-msd/usb-msd.h @@ -13,40 +13,20 @@ * If not, see . */ -#ifndef USBMSD_H -#define USBMSD_H +#pragma once + #include "USB/deviceproxy.h" namespace usb_msd { - - static const char* APINAME = "cstdio"; - - class MsdDevice + class MsdDevice final : public DeviceProxy { public: - virtual ~MsdDevice() {} - static USBDevice* CreateDevice(int port); - static const char* TypeName(); - static const TCHAR* Name() - { - return TEXT("Mass storage device"); - } - static std::list ListAPIs() - { - return std::list{APINAME}; - } - static const TCHAR* LongAPIName(const std::string& name) - { - return TEXT("cstdio"); - } - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* TypeName() const override; + const char* Name() const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override; + gsl::span Settings(u32 subtype) const override; }; - } // namespace usb_msd -#endif diff --git a/pcsx2/USB/usb-pad/api_init_linux.cpp b/pcsx2/USB/usb-pad/api_init_linux.cpp deleted file mode 100644 index 07ca03fe06..0000000000 --- a/pcsx2/USB/usb-pad/api_init_linux.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "padproxy.h" -#include "evdev/evdev.h" - -void usb_pad::RegisterPad::Register() -{ - auto& inst = RegisterPad::instance(); - inst.Add("evdev", new PadProxy()); -} diff --git a/pcsx2/USB/usb-pad/api_init_win32_pad.cpp b/pcsx2/USB/usb-pad/api_init_win32_pad.cpp deleted file mode 100644 index 64c64ffe0e..0000000000 --- a/pcsx2/USB/usb-pad/api_init_win32_pad.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "padproxy.h" -#include "raw/usb-pad-raw.h" -#include "dx/usb-pad-dx.h" - -void usb_pad::RegisterPad::Register() -{ - auto& inst = RegisterPad::instance(); - inst.Add(raw::APINAME, new PadProxy()); - inst.Add(dx::APINAME, new PadProxy()); -} diff --git a/pcsx2/USB/usb-pad/bitjuggling.cpp b/pcsx2/USB/usb-pad/bitjuggling.cpp deleted file mode 100644 index 6b0a9bcb57..0000000000 --- a/pcsx2/USB/usb-pad/bitjuggling.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "USB/qemu-usb/vl.h" - -#include -#include -#include - -// -// http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays -// - -#define PREPARE_FIRST_COPY() \ - do \ - { \ - if (src_len >= (CHAR_BIT - dst_offset_modulo)) \ - { \ - *dst &= reverse_mask[dst_offset_modulo]; \ - src_len -= CHAR_BIT - dst_offset_modulo; \ - } \ - else \ - { \ - *dst &= reverse_mask[dst_offset_modulo] | reverse_mask_xor[dst_offset_modulo + src_len + 1]; \ - c &= reverse_mask[dst_offset_modulo + src_len]; \ - src_len = 0; \ - } \ - } while (0) - -//But copies bits in reverse? -void bitarray_copy(const uint8_t* src_org, int src_offset, int src_len, - uint8_t* dst_org, int dst_offset) -{ - static const unsigned char mask[] = - {0x55, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; - static const unsigned char reverse_mask[] = - {0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; - static const unsigned char reverse_mask_xor[] = - {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00}; - - if (src_len) - { - const unsigned char* src; - unsigned char* dst; - int src_offset_modulo, - dst_offset_modulo; - - src = src_org + (src_offset / CHAR_BIT); - dst = dst_org + (dst_offset / CHAR_BIT); - - src_offset_modulo = src_offset % CHAR_BIT; - dst_offset_modulo = dst_offset % CHAR_BIT; - - if (src_offset_modulo == dst_offset_modulo) - { - int byte_len; - int src_len_modulo; - if (src_offset_modulo) - { - unsigned char c; - - c = reverse_mask_xor[dst_offset_modulo] & *src++; - - PREPARE_FIRST_COPY(); - *dst++ |= c; - } - - byte_len = src_len / CHAR_BIT; - src_len_modulo = src_len % CHAR_BIT; - - if (byte_len) - { - memcpy(dst, src, byte_len); - src += byte_len; - dst += byte_len; - } - if (src_len_modulo) - { - *dst &= reverse_mask_xor[src_len_modulo]; - *dst |= reverse_mask[src_len_modulo] & *src; - } - } - else - { - int bit_diff_ls, - bit_diff_rs; - int byte_len; - int src_len_modulo; - unsigned char c; - /* - * Begin: Line things up on destination. - */ - if (src_offset_modulo > dst_offset_modulo) - { - bit_diff_ls = src_offset_modulo - dst_offset_modulo; - bit_diff_rs = CHAR_BIT - bit_diff_ls; - - c = *src++ << bit_diff_ls; - c |= *src >> bit_diff_rs; - c &= reverse_mask_xor[dst_offset_modulo]; - } - else - { - bit_diff_rs = dst_offset_modulo - src_offset_modulo; - bit_diff_ls = CHAR_BIT - bit_diff_rs; - - c = *src >> bit_diff_rs & - reverse_mask_xor[dst_offset_modulo]; - } - PREPARE_FIRST_COPY(); - *dst++ |= c; - - /* - * Middle: copy with only shifting the source. - */ - byte_len = src_len / CHAR_BIT; - - while (--byte_len >= 0) - { - c = *src++ << bit_diff_ls; - c |= *src >> bit_diff_rs; - *dst++ = c; - } - - /* - * End: copy the remaing bits; - */ - src_len_modulo = src_len % CHAR_BIT; - if (src_len_modulo) - { - c = *src++ << bit_diff_ls; - c |= *src >> bit_diff_rs; - c &= reverse_mask[src_len_modulo]; - - *dst &= reverse_mask_xor[src_len_modulo]; - *dst |= c; - } - } - } -} diff --git a/pcsx2/USB/usb-pad/dx/dinput-config.cpp b/pcsx2/USB/usb-pad/dx/dinput-config.cpp deleted file mode 100644 index b3f846cb20..0000000000 --- a/pcsx2/USB/usb-pad/dx/dinput-config.cpp +++ /dev/null @@ -1,1479 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" - -#pragma warning(push) -// floats to int -#pragma warning(disable : 4244) - -#include "dx.h" - -#include -#include -#include -#include -#include "versionproxy.h" - -#include "usb-pad-dx.h" -#include "USB/shared/inifile_usb.h" - -namespace usb_pad -{ - namespace dx - { - - static int32_t useRamp = 0; - - bool listening = false; - DWORD listenend = 0; - DWORD listennext = 0; - DWORD listentimeout = 10000; - DWORD listeninterval = 500; - - extern BYTE diks[256]; // DirectInput keyboard state buffer - extern DIMOUSESTATE2 dims2; // DirectInput mouse state structure - - std::vector jso; // DInput joystick old state, only for config - std::vector jsi; // DInput joystick initial state, only for config - - int32_t GAINZ[2][1]; - int32_t FFMULTI[2][1]; - int32_t INVERTFORCES[2]{}; - - // FFB test - bool ffbTestRunning = false; - unsigned int ffbTestStage = 0; - - bool dialogOpen = false; - - HWND hKey; - HWND hWnd; - TCHAR text[1024]; - ControlID CID = CID_COUNT; //keep track of last assigned control - - HFONT hFont; - HDC hDC; - PAINTSTRUCT Ps; - RECT rect; - static WNDPROC pFnPrevFunc; - LONG filtercontrol = 0; - float TESTV = 0; - float TESTVF = 0; - DWORD m_dwScalingTime; - DWORD m_dwDrawingTime; - DWORD m_dwCreationTime; - DWORD m_dwMemory; - DWORD m_dwOption; - DWORD m_dwTime; - HBITMAP m_hOldAABitmap; - HBITMAP m_hAABitmap; - HDC m_hAADC; - HBITMAP m_hOldMemBitmap; - HBITMAP m_hMemBitmap; - HDC m_hMemDC; - - - //label enum - DWORD LABELS[CID_COUNT] = { - IDC_LABEL0, - IDC_LABEL1, - IDC_LABEL2, - IDC_LABEL3, - IDC_LABEL4, - IDC_LABEL5, - IDC_LABEL6, - IDC_LABEL7, - IDC_LABEL8, - IDC_LABEL9, - IDC_LABEL10, - IDC_LABEL11, - IDC_LABEL12, - IDC_LABEL13, - IDC_LABEL14, - IDC_LABEL15, - IDC_LABEL16, - IDC_LABEL17, - IDC_LABEL18, - IDC_LABEL19, - IDC_LABEL20, - IDC_LABEL21, - IDC_LABEL22, - IDC_LABEL23, - IDC_LABEL24, - IDC_LABEL25, - IDC_LABEL26, - IDC_LABEL27, - IDC_LABEL28, - IDC_LABEL29, - IDC_LABEL30, - }; - - struct DXDlgSettings - { - int port; - const char* dev_type; - }; - - void SetControlLabel(int cid, const InputMapped& im) - { - if (cid >= CID_COUNT) - return; - - if (im.type == MT_AXIS) - swprintf_s(text, L"Axis %zi/%i/%s/%i", im.index, im.mapped, im.INVERTED ? L"i" : L"n", im.HALF); - else if (im.type == MT_BUTTON) - swprintf_s(text, L"Button %zi/%i", im.index, im.mapped); - else - swprintf_s(text, L"Unmapped"); - - SetWindowText(GetDlgItem(hWnd, LABELS[cid]), text); - } - - //config only - void ListenUpdate() - { - for (size_t i = 0; i < g_pJoysticks.size(); i++) - { - jso[i] = g_pJoysticks[i]->GetDeviceState(); - } - PollDevices(); - } - - //poll and store all joystick states for comparison (config only) - void ListenAxis() - { - PollDevices(); - for (size_t i = 0; i < g_pJoysticks.size(); i++) - { - if (g_pJoysticks[i]->GetControlType() != CT_JOYSTICK) - continue; - jso[i] = g_pJoysticks[i]->GetDeviceState(); - jsi[i] = jso[i]; - } - - listenend = listentimeout + GetTickCount(); - listennext = GetTickCount(); - listening = true; - } - - //get listen time left in ms (config only) - DWORD GetListenTimeout() - { - return listenend - GetTickCount(); - } - - //compare all device axis for difference (config only) - bool AxisDown(size_t ijoy, InputMapped& im) - { - //TODO mouse axis - if (g_pJoysticks[ijoy]->GetControlType() != CT_JOYSTICK) - return false; - - DIJOYSTATE2 js = g_pJoysticks[ijoy]->GetDeviceState(); - LONG detectrange = 2000; - for (int32_t axisid = 0; axisid < DINPUT_AXES_COUNT; axisid++) - { - LONG diff = 0; - im.index = ijoy; - im.mapped = axisid; - im.type = MappingType::MT_NONE; - - // TODO mind the POV axes, one axis for all directions? - diff = GetAxisValueFromOffset(axisid, js) - GetAxisValueFromOffset(axisid, jso[ijoy]); - if (diff > detectrange) - { - im.HALF = GetAxisValueFromOffset(axisid, jsi[ijoy]); - im.INVERTED = true; - im.type = MappingType::MT_AXIS; - return true; - } - if (diff < -detectrange) - { - im.HALF = GetAxisValueFromOffset(axisid, jsi[ijoy]); - im.INVERTED = false; - im.type = MappingType::MT_AXIS; - return true; - } - } - return false; - } - - //checks all devices for digital button id/index - bool KeyDown(size_t ijoy, InputMapped& im) - { - assert(ijoy < g_pJoysticks.size()); - if (ijoy >= g_pJoysticks.size()) - return false; - - auto joy = g_pJoysticks[ijoy]; - im.index = ijoy; - im.type = MT_NONE; - - int buttons = 0; - - switch (joy->GetControlType()) - { - case CT_JOYSTICK: - buttons = ARRAY_SIZE(DIJOYSTATE2::rgbButtons) + 16 /* POV */; - break; - case CT_KEYBOARD: - buttons = 256; - break; - case CT_MOUSE: - buttons = ARRAY_SIZE(DIMOUSESTATE2::rgbButtons); - break; - default: - break; - } - - for (int b = 0; b < buttons; b++) - { - if (joy->GetButton(b)) - { - im.mapped = b; - im.type = MT_BUTTON; - return true; - } - } - - return false; - } - - //search all axis/buttons (config only) - bool FindControl(LONG port, ControlID cid, InputMapped& im) - { - if (listening == true) - { - if (listenend > GetTickCount()) - { - if (listennext < GetTickCount()) - { - listennext = listeninterval + GetTickCount(); - ListenUpdate(); - - for (size_t i = 0; i < g_pJoysticks.size(); i++) - { - if (AxisDown(i, im)) - { - listening = false; - if (CID_STEERING == cid) - { - CreateFFB(port, g_pJoysticks[im.index]->GetDevice(), im.mapped); - } - AddInputMap(port, cid, im); - return true; - } - else if (KeyDown(i, im)) - { - listening = false; - AddInputMap(port, cid, im); - return true; - } - } - } - } - else - { - GetInputMap(port, cid, im); - SetControlLabel(cid, im); - listening = false; - return false; //timedout - } - } - return false; - } - - void ApplyFilter(int port) - { - filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0); - - if (filtercontrol == -1) - return; - //slider - auto& im = g_Controls[port][filtercontrol]; - im.LINEAR = SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_GETPOS, 0, 0) - 50 * PRECMULTI; - im.OFFSET = SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_GETPOS, 0, 0) - 50 * PRECMULTI; - im.DEADZONE = SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_GETPOS, 0, 0) - 50 * PRECMULTI; - GAINZ[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_GETPOS, 0, 0); - FFMULTI[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_GETPOS, 0, 0); - - swprintf_s(text, TEXT("LINEARITY: %0.02f"), float(im.LINEAR) / PRECMULTI); - SetWindowText(GetDlgItem(hWnd, IDC_LINEAR), text); - swprintf_s(text, TEXT("OFFSET: %0.02f"), float(im.OFFSET) / PRECMULTI); - SetWindowText(GetDlgItem(hWnd, IDC_OFFSET), text); - swprintf_s(text, TEXT("DEAD-ZONE: %0.02f"), float(im.DEADZONE) / PRECMULTI); - SetWindowText(GetDlgItem(hWnd, IDC_DEADZONE), text); - - GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect); - MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2); - InvalidateRect(hWnd, &rect, TRUE); - } - - void LoadFilter(int port) - { - filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0); - if (filtercontrol == -1) - return; - auto& im = g_Controls[port][filtercontrol]; - //slider - SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_SETPOS, 1, im.LINEAR + 50 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_SETPOS, 1, im.OFFSET + 50 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_SETPOS, 1, im.DEADZONE + 50 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_SETPOS, 1, GAINZ[port][0]); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_SETPOS, 1, FFMULTI[port][0]); - - ApplyFilter(port); - } - - void DefaultFilters(int port, LONG id) - { - auto& im_l = g_Controls[port][CID_STEERING]; - auto& im_r = g_Controls[port][CID_STEERING_R]; - for (int i = 0; i < 6; i++) - { - auto& c = g_Controls[port][i]; - c.LINEAR = 0; - c.OFFSET = 0; - c.DEADZONE = 0; - } - - switch (id) - { - case 0: - im_l.LINEAR = 0; - im_l.OFFSET = 0; - im_r.LINEAR = 0; - im_r.OFFSET = 0; - break; - case 1: - im_l.LINEAR = 6 * PRECMULTI; - im_l.OFFSET = 0; - im_r.LINEAR = 6 * PRECMULTI; - im_r.OFFSET = 0; - break; - case 2: - im_l.LINEAR = 12 * PRECMULTI; - im_l.OFFSET = 0; - im_r.LINEAR = 12 * PRECMULTI; - im_r.OFFSET = 0; - break; - case 3: - im_l.LINEAR = 18 * PRECMULTI; - im_l.OFFSET = 0; - im_r.LINEAR = 18 * PRECMULTI; - im_r.OFFSET = 0; - break; - case 4: - im_l.LINEAR = 25 * PRECMULTI; - im_l.OFFSET = 0; - im_r.LINEAR = 25 * PRECMULTI; - im_r.OFFSET = 0; - break; - } - - LoadFilter(port); - } - - void ControlTest(int port) //thread: waits for window - { - InputMapped im; - - filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0); - if (filtercontrol >= 0 && listening == false) - { - PollDevices(); - - if (GetInputMap(port, (ControlID)filtercontrol, im)) - { - TESTV = ReadAxis(im); - TESTVF = FilterControl(ReadAxis(im), im.LINEAR, im.OFFSET, im.DEADZONE); - GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect); - MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2); - InvalidateRect(hWnd, &rect, TRUE); - } - } - else - { - TESTV = 0; - } - - return; - } - - void ListenForControl(int port) - { - InputMapped im({}); - - if (FindControl(port, CID, im)) - { - AddInputMap(port, CID, im); - SetControlLabel(CID, im); - } - else if (listening) - { - swprintf_s(text, L"Listening... %u", GetListenTimeout() / 1000 + 1); - SetWindowText(GetDlgItem(hWnd, LABELS[CID]), text); - } - } - - void StartListen(ControlID controlid) - { - if (listening) - return; - - CID = controlid; - swprintf_s(text, L"Listening..."); - SetWindowText(GetDlgItem(hWnd, LABELS[CID]), text); - ListenAxis(); - } - - void DeleteControl(int port, ControlID controlid) - { - CID = controlid; - RemoveInputMap(port, controlid); - SetWindowText(GetDlgItem(hWnd, LABELS[CID]), TEXT("Unmapped")); - } - - void CreateDrawing(int port, HDC hDrawingDC, int scale) - { - GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect); - //MapWindowPoints(GetDlgItem(hWnd,IDC_PICTURE), hWnd, (POINT *) &rect, 2); - - int px = 0; //rect.left; - int py = 0; //rect.top; - int pwidth = rect.right - rect.left; - int pheight = rect.bottom - rect.top; - - HPEN bluepen = CreatePen(PS_SOLID, 4 * scale, COLORREF RGB(79, 97, 117)); - HPEN gridpen = CreatePen(PS_SOLID, 1 * scale, COLORREF RGB(0, 0, 0)); - HPEN blackpen = CreatePen(PS_SOLID, 4 * scale, COLORREF RGB(0, 0, 0)); - HBRUSH hbrush = (HBRUSH)GetStockObject(LTGRAY_BRUSH); - - SelectObject(hDrawingDC, hbrush); - - rect.right *= scale; - rect.bottom *= scale; - - FillRect(hDrawingDC, &rect, hbrush); - - //draw grid - SelectObject(hDrawingDC, gridpen); - float step[2] = {pwidth / 5.f, pheight / 5.f}; - for (int x = 1; x < 5; x++) - { - MoveToEx(hDrawingDC, (step[0] * x + px) * scale, (py), 0); - LineTo(hDrawingDC, (step[0] * x + px) * scale, (pheight + py) * scale); - } - for (int y = 1; y < 5; y++) - { - MoveToEx(hDrawingDC, (px)*scale, (step[1] * y + py) * scale, 0); - LineTo(hDrawingDC, (pwidth + px) * scale, (step[1] * y + py) * scale); - } - - //draw linear line - SelectObject(hDrawingDC, blackpen); - MoveToEx(hDrawingDC, (px)*scale, (pheight + py) * scale, 0); - for (float x = 0; x < 1.0f; x += 0.001f) - { - LineTo(hDrawingDC, (x * pwidth + px) * scale, (-x * pheight + pheight + py) * scale); - } - - filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0); - if (filtercontrol >= 0) - { - auto& im = g_Controls[port][filtercontrol]; - - //draw nonlinear line - SelectObject(hDrawingDC, bluepen); - MoveToEx(hDrawingDC, (px + 8) * scale, (pheight + py - 8) * scale, 0); - for (float x = 0; x < 1.0f; x += 0.001f) - { - float y1 = FilterControl(x, im.LINEAR, im.OFFSET, im.DEADZONE); - LineTo(hDrawingDC, (x * (pwidth - 16) + px + 8) * scale, (-y1 * (pheight - 16) + (pheight - 8) + py) * scale); - } - LineTo(hDrawingDC, (1.0f * (pwidth - 16) + px + 8) * scale, (-1.0f * (pheight - 16) + (pheight - 8) + py) * scale); - - //draw output - int tx = (TESTV * (pwidth - 16) + px + 8) * scale; - int ty = (-TESTVF * (pheight - 16) + (pheight - 8) + py) * scale; - - Ellipse(hDrawingDC, tx - scale * 10, ty - scale * 10, tx + scale * 10, ty + scale * 10); - } - //cleanup - DeleteObject(bluepen); - DeleteObject(gridpen); - DeleteObject(blackpen); - } - - void CreateAAImage(int port, HDC hAADC, int scale) - { - GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect); - MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2); - - const int pwidth = rect.right - rect.left; - const int pheight = rect.bottom - rect.top; - - DWORD startTime, endTime; - - // Calculate memory requested - m_dwMemory = (scale * pwidth) * (scale * pheight) * 4; - - // Get screen DC - HDC hDC = ::GetDC(NULL); - - // Create temporary DC and bitmap - startTime = GetTickCount(); - HDC hTempDC = ::CreateCompatibleDC(hDC); - HBITMAP hTempBitmap = ::CreateCompatibleBitmap(hDC, scale * pwidth, scale * pheight); - HBITMAP hOldTempBitmap = (HBITMAP)::SelectObject(hTempDC, hTempBitmap); - endTime = GetTickCount(); - m_dwCreationTime = endTime - startTime; - - // Release screen DC - ::ReleaseDC(NULL, hDC); - - // Create drawing - startTime = GetTickCount(); - CreateDrawing(port, hTempDC, scale); - endTime = GetTickCount(); - m_dwDrawingTime = endTime - startTime; - - /* // Copy temporary DC to anti-aliazed DC - startTime = GetTickCount(); - int oldStretchBltMode = ::SetStretchBltMode(hAADC, HALFTONE); - ::StretchBlt(hAADC, 0, 0, 300, 200, hTempDC, 0, 0, scale*300, scale*200, SRCCOPY); - ::SetStretchBltMode(hAADC, oldStretchBltMode); - endTime = GetTickCount(); - m_dwScalingTime = endTime - startTime;*/ - - startTime = GetTickCount(); - - // Get source bits - int srcWidth = scale * pwidth; - int srcPitch = srcWidth * 4; - int srcSize = srcWidth * srcPitch; - BYTE* lpSrcBits = new BYTE[srcSize]; - GetBitmapBits(hTempBitmap, srcSize, lpSrcBits); - - // Get destination bits - int dstWidth = pwidth; - int dstHeight = pheight; - int dstPitch = dstWidth * 4; - int dstSize = dstWidth * dstPitch; - BYTE* lpDstBits = new BYTE[dstSize]; - HBITMAP hAABitmap = (HBITMAP)GetCurrentObject(hAADC, OBJ_BITMAP); - GetBitmapBits(hAABitmap, dstSize, lpDstBits); - - const int gridSize = scale * scale; - int resultRed, resultGreen, resultBlue; - int dstY = 0; - int tmpX, tmpY, tmpOffset; - for (int y = 1; y < dstHeight - 2; y++) - { - int dstX = 0; - const int srcY = (y * scale) * srcPitch; - for (int x = 1; x < dstWidth - 2; x++) - { - const int srcX = (x * scale) * 4; - const int srcOffset = srcY + srcX; - - resultRed = resultGreen = resultBlue = 0; - tmpY = -srcPitch; - for (int i = 0; i < scale; i++) - { - tmpX = -4; - for (int j = 0; j < scale; j++) - { - tmpOffset = tmpY + tmpX; - - resultRed += lpSrcBits[srcOffset + tmpOffset + 2]; - resultGreen += lpSrcBits[srcOffset + tmpOffset + 1]; - resultBlue += lpSrcBits[srcOffset + tmpOffset]; - - tmpX += 4; - } - tmpY += srcPitch; - } - - const int dstOffset = dstY + dstX; - lpDstBits[dstOffset + 2] = (BYTE)(resultRed / gridSize); - lpDstBits[dstOffset + 1] = (BYTE)(resultGreen / gridSize); - lpDstBits[dstOffset] = (BYTE)(resultBlue / gridSize); - dstX += 4; - } - - dstY += dstPitch; - } - SetBitmapBits(hAABitmap, dstSize, lpDstBits); - - // Destroy source bits - delete[] lpSrcBits; - - // Destroy destination bits - delete[] lpDstBits; - - endTime = GetTickCount(); - - m_dwScalingTime = endTime - startTime; - - // Destroy temporary DC and bitmap - if (hTempDC) - { - ::SelectObject(hTempDC, hOldTempBitmap); - ::DeleteDC(hTempDC); - ::DeleteObject(hTempBitmap); - } - } - - void InitialUpdate() - { - GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect); - MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2); - - int px = rect.left; - int py = rect.top; - int pwidth = rect.right - rect.left; - int pheight = rect.bottom - rect.top; - - // Get screen DC - HDC hDC = ::GetDC(NULL); - - // Create memory DC and bitmap - m_hMemDC = ::CreateCompatibleDC(hDC); - m_hMemBitmap = ::CreateCompatibleBitmap(hDC, pwidth, pheight); - m_hOldMemBitmap = (HBITMAP)::SelectObject(m_hMemDC, m_hMemBitmap); - - // Create anti-alias DC and bitmap - m_hAADC = ::CreateCompatibleDC(hDC); - m_hAABitmap = ::CreateCompatibleBitmap(hDC, pwidth, pheight); - m_hOldAABitmap = (HBITMAP)::SelectObject(m_hAADC, m_hAABitmap); - - // Release screen DC - ::ReleaseDC(NULL, hDC); - - // Create drawing - //CreateDrawing(m_hMemDC, 1); - //CreateAAImage(m_hAADC, 1); - } - - void OnPaint(int port) - { - GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect); - MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2); - - int px = rect.left; - int py = rect.top; - if (px <= 0 || py <= 0) - { - return; - } - int pwidth = rect.right - rect.left; - int pheight = rect.bottom - rect.top; - - //hDC = GetDC(hWnd);// - CreateAAImage(port, m_hAADC, 2); - - hDC = BeginPaint(hWnd, &Ps); - - //CreateDrawing(m_hAADC); - // Draw 2x2 anti-aliazed image - ::BitBlt(hDC, px + 2, py + 2, pwidth - 4, pheight - 4, m_hAADC, 0, 0, SRCCOPY); - - EndPaint(hWnd, &Ps); - } - - void EndFFBTest() - { - if (std::exchange(ffbTestRunning, false)) - { - KillTimer(hWnd, 23); - } - } - - INT_PTR CALLBACK StaticProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - (*pFnPrevFunc)(hDlg, uMsg, wParam, lParam); - switch (uMsg) - { - case WM_ERASEBKGND: - return TRUE; - case WM_PAINT: - break; - } - return TRUE; - } - - void InitDialog(int port, const char* dev_type) - { - hFont = CreateFont(18, - 0, - 0, - 0, - FW_BOLD, - 0, - 0, - 0, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH | FF_DONTCARE, - TEXT("Tahoma")); - HFONT hFont2 = CreateFont(14, - 0, - 0, - 0, - FW_BOLD, - 0, - 0, - 0, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH | FF_DONTCARE, - TEXT("Tahoma")); - - //pFnPrevFunc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hWnd,IDC_PICTURE),GWLP_WNDPROC,(LONG_PTR) StaticProc); - InitDirectInput(hWnd, port); - LoadDInputConfig(port, dev_type); // settings rely on GUIDs so load after device enum - FindFFDevice(port); - - jso.resize(g_pJoysticks.size()); - jsi.resize(g_pJoysticks.size()); - - InitCommonControls(); - - InitialUpdate(); - - SetTimer(hWnd, 22, 40, (TIMERPROC)NULL); - - //StartTest(); - const wchar_t* string[] = {L"STEER LEFT", L"STEER RIGHT", L"THROTTLE", L"BRAKE"}; - - for (int i = 0; i < 4; i++) - SendMessageW(GetDlgItem(hWnd, IDC_COMBO1), CB_ADDSTRING, 0, (LPARAM)string[i]); - - const wchar_t* stringp[] = {L"200 deg", L"360 deg", L"540 deg", L"720 deg", L"900 deg"}; - - for (int i = 0; i < 5; i++) - SendMessageW(GetDlgItem(hWnd, IDC_COMBO3), CB_ADDSTRING, 0, (LPARAM)stringp[i]); - - //slider - SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_SETPOS, 1, 50 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_SETPOS, 1, 50 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_SETPOS, 1, 50 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_SETRANGEMAX, 1, 100 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_SETRANGEMAX, 1, 100 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_SETRANGEMAX, 1, 100 * PRECMULTI); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_SETTICFREQ, 10 * PRECMULTI, 0); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_SETTICFREQ, 10 * PRECMULTI, 0); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_SETTICFREQ, 10 * PRECMULTI, 0); - - SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_SETRANGEMAX, 1, 10000); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_SETTICFREQ, 1000, 0); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_SETPOS, 1, GAINZ[port][0]); - - SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_SETRANGEMAX, 1, 10); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_SETTICFREQ, 1, 0); - SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_SETPOS, 1, FFMULTI[port][0]); - - SendMessage(GetDlgItem(hWnd, IDC_CHECK1), BM_SETCHECK, INVERTFORCES[port], 0); - SendMessage(GetDlgItem(hWnd, IDC_CHECK3), BM_SETCHECK, useRamp, 0); - //HANDLE hBitmap = LoadImage(NULL,MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP,0,0,LR_DEFAULTSIZE); - //SendMessage(GetDlgItem(hWnd,IDC_PICTURELINK), STM_SETIMAGE, IMAGE_BITMAP, LPARAM(hBitmap)); - - //fonts - SendMessage(GetDlgItem(hWnd, IDC_GROUP1), WM_SETFONT, (WPARAM)hFont, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP2), WM_SETFONT, (WPARAM)hFont, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP3), WM_SETFONT, (WPARAM)hFont, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP4), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP5), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP6), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP7), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP8), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP9), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP10), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP11), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP12), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP13), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP14), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP15), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP16), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP17), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP18), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP19), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP20), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP21), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP22), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP23), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP24), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP25), WM_SETFONT, (WPARAM)hFont2, 1); - SendMessage(GetDlgItem(hWnd, IDC_GROUP26), WM_SETFONT, (WPARAM)hFont2, 1); - - for (int i = 0; i < CID_COUNT; i++) - { - InputMapped im = {}; - GetInputMap(port, (ControlID)i, im); - SetControlLabel(i, im); - } - ShowWindow(hWnd, SW_SHOW); - - dialogOpen = true; - //UpdateWindow( hWnd ); - } - - INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - DXDlgSettings* s = nullptr; - //return false; - switch (uMsg) - { - case WM_CREATE: - SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam); - break; - - case WM_INITDIALOG: - { - s = (DXDlgSettings*)lParam; - hWnd = hDlg; - SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam); - InitDialog(s->port, s->dev_type); - } - break; - case WM_CTLCOLORSTATIC: - { - if ((HWND)lParam == GetDlgItem(hWnd, IDC_GROUP1) || (HWND)lParam == GetDlgItem(hWnd, IDC_GROUP2) || (HWND)lParam == GetDlgItem(hWnd, IDC_GROUP3)) - { - SetTextColor((HDC)wParam, RGB(79, 97, 117)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetStockObject(NULL_BRUSH); - } - if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL1) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL1) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL1) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL1)) - { - SetTextColor((HDC)wParam, RGB(255, 0, 0)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetStockObject(NULL_BRUSH); - } - if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL2) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL2) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL2) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL2)) - { - SetTextColor((HDC)wParam, RGB(0, 192, 255)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetStockObject(NULL_BRUSH); - } - if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL3) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL3) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL3) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL3)) - { - SetTextColor((HDC)wParam, RGB(255, 165, 0)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetStockObject(NULL_BRUSH); - } - if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL4) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL4) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL4) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL4)) - { - SetTextColor((HDC)wParam, RGB(0, 140, 0)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetStockObject(NULL_BRUSH); - } - if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL5) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL5) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL5) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL5)) - { - SetTextColor((HDC)wParam, RGB(204, 204, 0)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetStockObject(NULL_BRUSH); - } - - break; - } - case WM_TIMER: - { - - switch (wParam) - { - case 22: - { - s = (DXDlgSettings*)GetWindowLongPtr(hDlg, GWLP_USERDATA); - if (listening) - ListenForControl(s->port); - ControlTest(s->port); - break; - } - case 23: - { - s = (DXDlgSettings*)GetWindowLongPtr(hDlg, GWLP_USERDATA); - if (!UpdateTestForce(s->port, ffbTestStage++)) - { - EndTestForce(s->port); - EndFFBTest(); - } - break; - } - } - break; - } - - case WM_COMMAND: - s = (DXDlgSettings*)GetWindowLongPtr(hDlg, GWLP_USERDATA); - switch (LOWORD(wParam)) - { - case IDC_COMBO1: - switch (HIWORD(wParam)) - { - case CBN_SELCHANGE: - LoadFilter(s->port); - break; - } - break; - case IDC_COMBO3: - switch (HIWORD(wParam)) - { - case CBN_SELCHANGE: - DefaultFilters(s->port, SendMessage(GetDlgItem(hWnd, IDC_COMBO3), CB_GETCURSEL, 0, 0)); - SendMessage(GetDlgItem(hWnd, IDC_COMBO3), CB_SETCURSEL, -1, 0); - break; - } - break; - case IDC_COMBO4: - switch (HIWORD(wParam)) - { - case LBN_SELCHANGE: - //selectedJoy[0] = SendDlgItemMessage(hWnd, IDC_COMBO4, CB_GETCURSEL, 0, 0); - break; - } - break; - - case IDOK: - { - ApplySettings(s->port); - SaveDInputConfig(s->port, s->dev_type); - SaveConfig(); // Force save to ini file - //Seems to create some dead locks - //SendMessage(hWnd, WM_CLOSE, 0, 0); - //return TRUE; - dialogOpen = false; - EndFFBTest(); - FreeDirectInput(); - EndDialog(hWnd, TRUE); - return TRUE; - } - //break; //Fall through - case IDCANCEL: - { - //Seems to create some dead locks - //SendMessage(hWnd, WM_CLOSE, 0, 0); - dialogOpen = false; - EndFFBTest(); - FreeDirectInput(); - EndDialog(hWnd, FALSE); - return TRUE; - } - break; - case IDC_BUTTON1: - { - if (!ffbTestRunning) - { - ApplySettings(s->port); - if (StartTestForce(s->port)) - { - if (UpdateTestForce(s->port, 0)) - { - // Start a timer to "tick" the FFB test every 500ms - ffbTestStage = 1; - SetTimer(hWnd, 23, 500, nullptr); - ffbTestRunning = true; - } - } - } - } - break; - case IDC_DELALL: - { - for (int i = 0; i < CID_COUNT; i++) - { - DeleteControl(s->port, (ControlID)i); - } - } - break; - - case IDC_ASS0: - { - StartListen(CID_STEERING); - break; - } - case IDC_ASS1: - { - StartListen(CID_STEERING_R); - break; - } - case IDC_ASS2: - { - StartListen(CID_THROTTLE); - break; - } - case IDC_ASS3: - { - StartListen(CID_BRAKE); - break; - } - case IDC_ASS4: - { - StartListen(CID_HATUP); - break; - } - case IDC_ASS5: - { - StartListen(CID_HATDOWN); - break; - } - case IDC_ASS6: - { - StartListen(CID_HATLEFT); - break; - } - case IDC_ASS7: - { - StartListen(CID_HATRIGHT); - break; - } - case IDC_ASS8: - { - StartListen(CID_SQUARE); - break; - } - case IDC_ASS9: - { - StartListen(CID_TRIANGLE); - break; - } - case IDC_ASS10: - { - StartListen(CID_CROSS); - break; - } - case IDC_ASS11: - { - StartListen(CID_CIRCLE); - break; - } - case IDC_ASS12: - { - StartListen(CID_L1); - break; - } - case IDC_ASS13: - { - StartListen(CID_R1); - break; - } - case IDC_ASS14: - { - StartListen(CID_L2); - break; - } - case IDC_ASS15: - { - StartListen(CID_R2); - break; - } - case IDC_ASS16: - { - StartListen(CID_L3); - break; - } - case IDC_ASS17: - { - StartListen(CID_R3); - break; - } - case IDC_ASS18: - { - StartListen(CID_SELECT); - break; - } - case IDC_ASS19: - { - StartListen(CID_START); - break; - } - case IDC_ASS20: - { - StartListen(CID_BUTTON20); - break; - } - case IDC_ASS21: - { - StartListen(CID_BUTTON21); - break; - } - case IDC_ASS22: - { - StartListen(CID_BUTTON22); - break; - } - case IDC_ASS23: - { - StartListen(CID_BUTTON23); - break; - } - case IDC_ASS24: - { - StartListen(CID_BUTTON24); - break; - } - case IDC_ASS25: - { - StartListen(CID_BUTTON25); - break; - } - case IDC_ASS26: - { - StartListen(CID_BUTTON26); - break; - } - case IDC_ASS27: - { - StartListen(CID_BUTTON27); - break; - } - case IDC_ASS28: - { - StartListen(CID_BUTTON28); - break; - } - case IDC_ASS29: - { - StartListen(CID_BUTTON29); - break; - } - case IDC_ASS30: - { - StartListen(CID_BUTTON30); - break; - } - case IDC_DEL0: - { - DeleteControl(s->port, CID_STEERING); - break; - } - case IDC_DEL1: - { - DeleteControl(s->port, CID_STEERING_R); - break; - } - case IDC_DEL2: - { - DeleteControl(s->port, CID_THROTTLE); - break; - } - case IDC_DEL3: - { - DeleteControl(s->port, CID_BRAKE); - break; - } - case IDC_DEL4: - { - DeleteControl(s->port, CID_HATUP); - break; - } - case IDC_DEL5: - { - DeleteControl(s->port, CID_HATDOWN); - break; - } - case IDC_DEL6: - { - DeleteControl(s->port, CID_HATLEFT); - break; - } - case IDC_DEL7: - { - DeleteControl(s->port, CID_HATRIGHT); - break; - } - case IDC_DEL8: - { - DeleteControl(s->port, CID_SQUARE); - break; - } - case IDC_DEL9: - { - DeleteControl(s->port, CID_TRIANGLE); - break; - } - case IDC_DEL10: - { - DeleteControl(s->port, CID_CROSS); - break; - } - case IDC_DEL11: - { - DeleteControl(s->port, CID_CIRCLE); - break; - } - case IDC_DEL12: - { - DeleteControl(s->port, CID_L1); - break; - } - case IDC_DEL13: - { - DeleteControl(s->port, CID_R1); - break; - } - case IDC_DEL14: - { - DeleteControl(s->port, CID_L2); - break; - } - case IDC_DEL15: - { - DeleteControl(s->port, CID_R2); - break; - } - case IDC_DEL16: - { - DeleteControl(s->port, CID_L3); - break; - } - case IDC_DEL17: - { - DeleteControl(s->port, CID_R3); - break; - } - case IDC_DEL18: - { - DeleteControl(s->port, CID_SELECT); - break; - } - case IDC_DEL19: - { - DeleteControl(s->port, CID_START); - break; - } - - - case IDC_PICTURELINK1: - { - ShellExecuteA(NULL, "open", "http://www.ecsimhardware.com", NULL, NULL, SW_SHOWNORMAL); - break; - } - case IDC_PICTURELINK2: - { - ShellExecuteA(NULL, "open", "http://www.ecsimshop.com", NULL, NULL, SW_SHOWNORMAL); - break; - } - case IDC_PICTURELINK3: - { - ShellExecuteA(NULL, "open", "http://www.tocaedit.com", NULL, NULL, SW_SHOWNORMAL); - break; - } - } - break; - - case WM_CLOSE: - { - dialogOpen = false; - EndFFBTest(); - FreeDirectInput(); - EndDialog(hWnd, 0); - } - break; - - case WM_DESTROY: - //PostQuitMessage(0); - return TRUE; - break; - case WM_HSCROLL: - s = (DXDlgSettings*)GetWindowLongPtr(hDlg, GWLP_USERDATA); - ApplyFilter(s->port); - break; - case WM_PAINT: - s = (DXDlgSettings*)GetWindowLongPtr(hDlg, GWLP_USERDATA); - OnPaint(s->port); - break; - } - - return FALSE; - } - - void ApplySettings(int port) - { - INVERTFORCES[port] = SendDlgItemMessage(hWnd, IDC_CHECK1, BM_GETCHECK, 0, 0); - useRamp = !!SendDlgItemMessage(hWnd, IDC_CHECK3, BM_GETCHECK, 0, 0); - GAINZ[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_GETPOS, 0, 0); - FFMULTI[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_GETPOS, 0, 0); - } - - void SaveDInputConfig(int port, const char* dev_type) - { - wchar_t section[256]; - swprintf_s(section, L"%S dinput %d", dev_type, port); - - ClearSection(section); - SaveSetting(section, TEXT("INVERTFORCES"), INVERTFORCES[port]); - -#ifdef _WIN32 - SaveSetting(section, TEXT("# CONTROL n"), str_to_wstr("GUID,MAPPING TYPE,MAPPED TO,INVERTED,HALF,LINEAR,OFFSET,DEADZONE")); -#else - SaveSetting(section, TEXT("# CONTROL n"), "GUID,MAPPING TYPE,MAPPED TO,INVERTED,HALF,LINEAR,OFFSET,DEADZONE"); -#endif - - for (auto& control : g_Controls[port]) - { - int cid = control.first; - const InputMapped& im = control.second; - auto joy = g_pJoysticks[im.index]; - - std::stringstream ss; - ss << joy->GetGUID() << "," << im.type << "," << im.mapped; - //SaveSetting(section, TEXT("ProductName"), joy->Product()); - - if (joy->GetControlType() == CT_JOYSTICK) - { - ss << "," << im.INVERTED - << "," << im.HALF - << "," << im.LINEAR - << "," << im.OFFSET - << "," << im.DEADZONE; - } - - swprintf_s(text, TEXT("CONTROL %i"), cid); -#ifdef _WIN32 - SaveSetting(section, text, str_to_wstr(ss.str())); -#else - SaveSetting(section, text, ss.str()); -#endif - } - - SaveSetting(section, TEXT("GAINZ"), GAINZ[port][0]); - SaveSetting(section, TEXT("FFMULTI"), FFMULTI[port][0]); - //only for config dialog - SaveSetting(section, TEXT("UseRamp"), useRamp); - } - - void LoadDInputConfig(int port, const char* dev_type) - { - wchar_t section[256]; - swprintf_s(section, L"%S dinput %d", dev_type, port); - - LoadSetting(section, TEXT("INVERTFORCES"), INVERTFORCES[port]); - if (!LoadSetting(section, TEXT("GAINZ"), GAINZ[port][0])) - GAINZ[port][0] = DI_FFNOMINALMAX; - - if (!LoadSetting(section, TEXT("FFMULTI"), FFMULTI[port][0])) - FFMULTI[port][0] = 0; - - try - { - swprintf_s(section, TEXT("%" SFMTs " dinput %d"), dev_type, port); - - for (int cid = 0; cid < CID_COUNT; cid++) - { - InputMapped im = {}; - bool found = false; - std::string control, guid, value; - std::stringstream ss; - - swprintf_s(text, TEXT("CONTROL %i"), cid); -#ifdef _WIN32 - std::wstring tmp; - bool res_control = LoadSetting(section, text, tmp); - control = wstr_to_str(tmp); - if (!res_control) - continue; -#else - if (!LoadSetting(section, text, control)) - continue; -#endif - - ss << control; - std::getline(ss, guid, ','); - - for (size_t i = 0; i < g_pJoysticks.size(); i++) - { - std::stringstream ss_guid; - ss_guid << g_pJoysticks[i]->GetGUID(); - if (ss_guid.str() == guid) - { - im.index = i; - found = true; - break; - } - } - - if (!found) - continue; - - std::getline(ss, value, ','); - im.type = (MappingType)std::stoi(value); - - if (im.type == MT_NONE) - { - continue; - } - - std::getline(ss, value, ','); - im.mapped = std::stoi(value); - - if (g_pJoysticks[im.index]->GetControlType() == CT_JOYSTICK) - { - std::getline(ss, value, ','); - im.INVERTED = std::stoi(value); - std::getline(ss, value, ','); - im.HALF = std::stoi(value); - std::getline(ss, value, ','); - im.LINEAR = std::stoi(value); - std::getline(ss, value, ','); - im.OFFSET = std::stoi(value); - std::getline(ss, value, ','); - im.DEADZONE = std::stoi(value); - } - - AddInputMap(port, (ControlID)cid, im); - } - } - catch (std::exception&) - { - } - - LoadSetting(section, TEXT("UseRamp"), useRamp); - } - - int DInputPad::Configure(int port, const char* dev_type, void* data) - { - Win32Handles h = *(Win32Handles*)data; - struct DXDlgSettings s; - s.port = port; - s.dev_type = dev_type; - if (strcmp(dev_type, BuzzDevice::TypeName()) == 0) - { - return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_BUZZ), h.hWnd, DxDialogProc, (LPARAM)&s); - } - if (strcmp(dev_type, KeyboardmaniaDevice::TypeName()) == 0) - { - return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_KEYBOARDMANIA), h.hWnd, DxDialogProc, (LPARAM)&s); - } - if (strcmp(dev_type, GametrakDevice::TypeName()) == 0) - { - return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_GAMETRAK), h.hWnd, DxDialogProc, (LPARAM)&s); - } - if (strcmp(dev_type, RealPlayDevice::TypeName()) == 0) - { - return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_REALPLAY), h.hWnd, DxDialogProc, (LPARAM)&s); - } - return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DIALOG1), h.hWnd, DxDialogProc, (LPARAM)&s); - } - - } // namespace dx -} // namespace usb_pad -#pragma warning(pop) diff --git a/pcsx2/USB/usb-pad/dx/dinput.cpp b/pcsx2/USB/usb-pad/dx/dinput.cpp deleted file mode 100644 index 10c040d9be..0000000000 --- a/pcsx2/USB/usb-pad/dx/dinput.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include -#include -#include "dx.h" - -#define SAFE_DELETE(p) \ - { \ - if (p) \ - { \ - delete (p); \ - (p) = NULL; \ - } \ - } -#define SAFE_RELEASE(p) \ - { \ - if (p) \ - { \ - (p)->Release(); \ - (p) = NULL; \ - } \ - } - -//dialog window stuff -extern HWND gsWnd; - -namespace usb_pad -{ - namespace dx - { - - static std::atomic refCount(0); - static bool useRamp = false; - - DWORD pid = 0; - DWORD old = 0; - - static LPDIRECTINPUT8 g_pDI = NULL; - - std::vector g_pJoysticks; - std::map g_Controls[2]; - - static DWORD rgdwAxes[1] = {DIJOFS_X}; //FIXME if steering uses two axes, then this needs DIJOFS_Y too? - static LONG rglDirection[1] = {0}; - - //only two effect (constant force, spring) - static bool FFB[2] = {false, false}; - static LPDIRECTINPUTEFFECT g_pEffectConstant[2] = {0, 0}; - static LPDIRECTINPUTEFFECT g_pEffectSpring[2] = {0, 0}; - static LPDIRECTINPUTEFFECT g_pEffectFriction[2] = {0, 0}; //DFP mode only - static LPDIRECTINPUTEFFECT g_pEffectRamp[2] = {0, 0}; - static LPDIRECTINPUTEFFECT g_pEffectDamper[2] = {0, 0}; - static DWORD g_dwNumForceFeedbackAxis[4] = {0}; - static DIEFFECT eff; - static DIEFFECT effSpring; - static DIEFFECT effFriction; - static DIEFFECT effRamp; - static DIEFFECT effDamper; - static DICONSTANTFORCE cfw; - static DICONDITION cSpring; - static DICONDITION cFriction; - static DIRAMPFORCE cRamp; - static DICONDITION cDamper; - - std::ostream& operator<<(std::ostream& os, REFGUID guid) - { - std::ios_base::fmtflags f(os.flags()); - os << std::uppercase; - os.width(8); - os << std::hex << guid.Data1 << '-'; - - os.width(4); - os << std::hex << guid.Data2 << '-'; - - os.width(4); - os << std::hex << guid.Data3 << '-'; - - os.width(2); - os << std::hex - << static_cast(guid.Data4[0]) - << static_cast(guid.Data4[1]) - << '-' - << static_cast(guid.Data4[2]) - << static_cast(guid.Data4[3]) - << static_cast(guid.Data4[4]) - << static_cast(guid.Data4[5]) - << static_cast(guid.Data4[6]) - << static_cast(guid.Data4[7]); - os.flags(f); - return os; - } - - LONG GetAxisValueFromOffset(int axis, const DIJOYSTATE2& j) - { - constexpr int LVX_OFFSET = 8; // count POVs or not? - switch (axis) - { - case 0: - return j.lX; - break; - case 1: - return j.lY; - break; - case 2: - return j.lZ; - break; - case 3: - return j.lRx; - break; - case 4: - return j.lRy; - break; - case 5: - return j.lRz; - break; - case 6: - return j.rglSlider[0]; - break; - case 7: - return j.rglSlider[1]; - break; - //case 8: return j.rgdwPOV[0]; break; - //case 9: return j.rgdwPOV[1]; break; - //case 10: return j.rgdwPOV[2]; break; - //case 11: return j.rgdwPOV[3]; break; - case LVX_OFFSET + 0: - return j.lVX; - break; /* 'v' as in velocity */ - case LVX_OFFSET + 1: - return j.lVY; - break; - case LVX_OFFSET + 2: - return j.lVZ; - break; - case LVX_OFFSET + 3: - return j.lVRx; - break; - case LVX_OFFSET + 4: - return j.lVRy; - break; - case LVX_OFFSET + 5: - return j.lVRz; - break; - case LVX_OFFSET + 6: - return j.rglVSlider[0]; - break; - case LVX_OFFSET + 7: - return j.rglVSlider[1]; - break; - case LVX_OFFSET + 8: - return j.lAX; - break; /* 'a' as in acceleration */ - case LVX_OFFSET + 9: - return j.lAY; - break; - case LVX_OFFSET + 10: - return j.lAZ; - break; - case LVX_OFFSET + 11: - return j.lARx; - break; - case LVX_OFFSET + 12: - return j.lARy; - break; - case LVX_OFFSET + 13: - return j.lARz; - break; - case LVX_OFFSET + 14: - return j.rglASlider[0]; - break; - case LVX_OFFSET + 15: - return j.rglASlider[1]; - break; - case LVX_OFFSET + 16: - return j.lFX; - break; /* 'f' as in force */ - case LVX_OFFSET + 17: - return j.lFY; - break; - case LVX_OFFSET + 18: - return j.lFZ; - break; - case LVX_OFFSET + 19: - return j.lFRx; - break; /* 'fr' as in rotational force aka torque */ - case LVX_OFFSET + 20: - return j.lFRy; - break; - case LVX_OFFSET + 21: - return j.lFRz; - break; - case LVX_OFFSET + 22: - return j.rglFSlider[0]; - break; - case LVX_OFFSET + 23: - return j.rglFSlider[1]; - break; - } - return 0; - } - - bool JoystickDevice::Poll() - { - HRESULT hr = 0; - if (m_device) - { - hr = m_device->Poll(); - if (FAILED(hr)) - { - hr = m_device->Acquire(); - //return SUCCEEDED(hr); - } - else - { - if (m_type == CT_JOYSTICK) - { - m_device->GetDeviceState(sizeof(m_controls.js2), &m_controls.js2); - } - else if (m_type == CT_MOUSE) - { - m_device->GetDeviceState(sizeof(m_controls.ms2), &m_controls.ms2); - } - else if (m_type == CT_KEYBOARD) - { - m_device->GetDeviceState(sizeof(m_controls.kbd), &m_controls.kbd); - } - return true; - } - } - return false; - } - - bool JoystickDevice::GetButton(int b) - { - if (m_type == CT_JOYSTICK) - { - if (b < ARRAY_SIZE(DIJOYSTATE2::rgbButtons) && m_controls.js2.rgbButtons[b] & 0x80) - return true; - - if (b >= ARRAY_SIZE(DIJOYSTATE2::rgbButtons)) - { - b -= ARRAY_SIZE(DIJOYSTATE2::rgbButtons); - int i = b / 4; - //hat switch cases (4 hat switches with 4 directions possible) surely a better way... but this would allow funky joysticks to work. - switch (b % 4) - { - case 0: - if ((m_controls.js2.rgdwPOV[i] <= 4500 || m_controls.js2.rgdwPOV[i] >= 31500) && m_controls.js2.rgdwPOV[i] != -1) - { - return true; - } - break; - case 1: - if (m_controls.js2.rgdwPOV[i] >= 4500 && m_controls.js2.rgdwPOV[i] <= 13500) - { - return true; - } - break; - case 2: - if (m_controls.js2.rgdwPOV[i] >= 13500 && m_controls.js2.rgdwPOV[i] <= 22500) - { - return true; - } - break; - case 3: - if (m_controls.js2.rgdwPOV[i] >= 22500 && m_controls.js2.rgdwPOV[i] <= 31500) - { - return true; - } - break; - } - } - } - else if (m_type == CT_KEYBOARD) - { - return (b < ARRAY_SIZE(m_controls.kbd) && m_controls.kbd[b] & 0x80); - } - else if (m_type == CT_MOUSE) - { - return (b < ARRAY_SIZE(DIMOUSESTATE2::rgbButtons) && m_controls.ms2.rgbButtons[b] & 0x80); - } - return false; - } - - LONG JoystickDevice::GetAxis(int a) - { - return GetAxisValueFromOffset(a, m_controls.js2); - } - - JoystickDevice::~JoystickDevice() - { - if (m_device) - { - m_device->Unacquire(); - m_device->Release(); - } - } - - void ReleaseFFB(int port) - { - if (g_pEffectConstant[port]) - g_pEffectConstant[port]->Stop(); - if (g_pEffectSpring[port]) - g_pEffectSpring[port]->Stop(); - if (g_pEffectFriction[port]) - g_pEffectFriction[port]->Stop(); - if (g_pEffectRamp[port]) - g_pEffectRamp[port]->Stop(); - if (g_pEffectDamper[port]) - g_pEffectDamper[port]->Stop(); - - SAFE_RELEASE(g_pEffectConstant[port]); - SAFE_RELEASE(g_pEffectSpring[port]); - SAFE_RELEASE(g_pEffectFriction[port]); - SAFE_RELEASE(g_pEffectRamp[port]); - SAFE_RELEASE(g_pEffectDamper[port]); - - FFB[port] = false; - } - - void AddInputMap(int port, int cid, const InputMapped& im) - { - g_Controls[port][cid] = im; - } - - void RemoveInputMap(int port, int cid) - { - g_Controls[port].erase(cid); //FIXME ini doesn't clear old entries duh - // override with MT_NONE instead - //g_Controls[port][cid].type = MT_NONE; - } - - bool GetInputMap(int port, int cid, InputMapped& im) - { - auto it = g_Controls[port].find(cid); - if (it != g_Controls[port].end()) - { - im = it->second; - return true; - } - return false; - } - - void CreateFFB(int port, LPDIRECTINPUTDEVICE8 device, DWORD axis) - { - ReleaseFFB(port); - - if (!device) - return; - - UpdateFFBSettings(port, device); - - rgdwAxes[0] = axis; - //LPDIRECTINPUTDEVICE8 device = joy->GetDevice(); - //create the constant force effect - ZeroMemory(&eff, sizeof(eff)); - ZeroMemory(&effSpring, sizeof(effSpring)); - ZeroMemory(&effFriction, sizeof(effFriction)); - ZeroMemory(&cfw, sizeof(cfw)); - ZeroMemory(&cSpring, sizeof(cSpring)); - ZeroMemory(&cFriction, sizeof(cFriction)); - ZeroMemory(&cRamp, sizeof(cRamp)); - - //constantforce - eff.dwSize = sizeof(eff); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.dwSamplePeriod = 0; - eff.dwGain = DI_FFNOMINALMAX; - eff.dwTriggerButton = DIEB_NOTRIGGER; - eff.dwTriggerRepeatInterval = 0; - eff.cAxes = countof(rgdwAxes); - eff.rgdwAxes = rgdwAxes; //TODO set actual "steering" axis though usually is DIJOFS_X - eff.rglDirection = rglDirection; - eff.dwStartDelay = 0; - eff.dwDuration = INFINITE; - - // copy default values - effSpring = eff; - effFriction = eff; - effRamp = eff; - effDamper = eff; - - cfw.lMagnitude = 0; - - eff.cbTypeSpecificParams = sizeof(cfw); - eff.lpvTypeSpecificParams = &cfw; - { - HRESULT hres = device->CreateEffect(GUID_ConstantForce, &eff, &g_pEffectConstant[port], NULL); - if (FAILED(hres)) - Console.Warning("USB: CreateEffect GUID_ConstantForce error: %x", hres); - } - - cSpring.lNegativeCoefficient = 0; - cSpring.lPositiveCoefficient = 0; - - effSpring.cbTypeSpecificParams = sizeof(cSpring); - effSpring.lpvTypeSpecificParams = &cSpring; - { - HRESULT hres = device->CreateEffect(GUID_Spring, &effSpring, &g_pEffectSpring[port], NULL); - if (FAILED(hres)) - Console.Warning("USB: CreateEffect GUID_Spring error: %x", hres); - } - - effFriction.cbTypeSpecificParams = sizeof(cFriction); - effFriction.lpvTypeSpecificParams = &cFriction; - { - HRESULT hres = device->CreateEffect(GUID_Friction, &effFriction, &g_pEffectFriction[port], NULL); - if (FAILED(hres)) - Console.Warning("USB: CreateEffect GUID_Friction error: %x", hres); - } - - effRamp.cbTypeSpecificParams = sizeof(cRamp); - effRamp.lpvTypeSpecificParams = &cRamp; - { - HRESULT hres = device->CreateEffect(GUID_RampForce, &effRamp, &g_pEffectRamp[port], NULL); - if (FAILED(hres)) - Console.Warning("USB: CreateEffect GUID_RampForce error: %x", hres); - } - - effDamper.cbTypeSpecificParams = sizeof(cDamper); - effDamper.lpvTypeSpecificParams = &cDamper; - { - HRESULT hres = device->CreateEffect(GUID_Damper, &effDamper, &g_pEffectDamper[port], NULL); - if (FAILED(hres)) - Console.Warning("USB: CreateEffect GUID_Damper error: %x", hres); - } - - FFB[port] = true; - - //start the effect - if (g_pEffectConstant[port]) - { - g_pEffectConstant[port]->Start(1, 0); - } - } - - bool UpdateFFBSettings(int port, LPDIRECTINPUTDEVICE8 device) - { - DIPROPDWORD prop { sizeof(prop), sizeof(prop.diph) }; - prop.diph.dwObj = 0; - prop.diph.dwHow = DIPH_DEVICE; - prop.dwData = std::clamp(GAINZ[port][0], 0, DI_FFNOMINALMAX); - return SUCCEEDED(device->SetProperty(DIPROP_FFGAIN, &prop.diph)); - } - - BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext) - { - HRESULT hr; - - // Obtain an interface to the enumerated joystick. - LPDIRECTINPUTDEVICE8 joy = nullptr; - hr = g_pDI->CreateDevice(pdidInstance->guidInstance, &joy, NULL); - if (SUCCEEDED(hr) && joy) - g_pJoysticks.push_back(new JoystickDevice(CT_JOYSTICK, joy, pdidInstance->guidInstance, pdidInstance->tszProductName)); - - return DIENUM_CONTINUE; - } - - BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext) - { - HRESULT hr; - LPDIRECTINPUTDEVICE8 pWheel = (LPDIRECTINPUTDEVICE8)pContext; - // For axes that are returned, set the DIPROP_RANGE property for the - // enumerated axis in order to scale min/max values. - if (pdidoi->dwType & DIDFT_AXIS) - { - DIPROPRANGE diprg { sizeof(diprg), sizeof(diprg.diph) }; - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis - diprg.lMin = 0; - diprg.lMax = 65535; - - // Set the range for the axis (not used, DX defaults 65535 all axis) - if (FAILED(hr = pWheel->SetProperty(DIPROP_RANGE, &diprg.diph))) - return DIENUM_STOP; - - //DIPROPDWORD dipdw; - //dipdw.diph.dwSize = sizeof(DIPROPDWORD); - //dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - //dipdw.diph.dwHow = DIPH_BYID; //DIPH_DEVICE; - //dipdw.diph.dwObj = pdidoi->dwType; //0; - //dipdw.dwData = DIPROPAXISMODE_ABS; - - //if (FAILED(hr = pWheel->SetProperty(DIPROP_AXISMODE, &dipdw.diph))) - // return DIENUM_CONTINUE; - - //dipdw.dwData = 0; - //if (FAILED(hr = pWheel->SetProperty(DIPROP_DEADZONE, &dipdw.diph))) - // return DIENUM_CONTINUE; - - //dipdw.dwData = DI_FFNOMINALMAX; - //if (FAILED(hr = pWheel->SetProperty(DIPROP_SATURATION, &dipdw.diph))) - // return DIENUM_CONTINUE; - } - - return DIENUM_CONTINUE; - } - - //read all joystick states - void PollDevices() - { - for (auto& joy : g_pJoysticks) - { - joy->Poll(); - } - } - - //the non-linear filter (input/output 0.0-1.0 only) (parameters -50 to +50, expanded with PRECMULTI) - float FilterControl(float input, LONG linear, LONG offset, LONG dead) - { - //ugly, but it works gooood - - //format+shorten variables - float lf = float(linear) / PRECMULTI; - float hs = 0; - if (linear > 0) - hs = 1.0f - ((lf * 2) * 0.01f); - else - hs = 1.0f - (abs(lf * 2) * 0.01f); - - float hs2 = (offset + 50 * PRECMULTI) / PRECMULTI * 0.01f; - float v = input; - float d = float(dead) / PRECMULTI * 0.005f; - - //format and apply deadzone - v = (v * (1.0f + (d * 2.0f))) - d; - - //clamp - if (v < 0.0f) - v = 0.0f; - if (v > 1.0f) - v = 1.0f; - - //clamp negdead - //if (v == -d) v = 0.0; - if (fabs(v + d) < FLT_EPSILON) - v = 0.0f; - - //possibilities - float c1 = v - (1.0f - (pow((1.0f - v), (1.0f / hs)))); - float c2 = v - pow(v, hs); - float c3 = float(v - (1.0 - (pow((1.0 - v), hs)))); - float c4 = ((v - pow(v, (1.0f / hs)))); - float res = 0; - - if (linear < 0) - { - res = v - (((1.0f - hs2) * c3) + (hs2 * c4)); //get negative result - } - else - { - res = v - (((1.0f - hs2) * c1) + (hs2 * c2)); //get positive result - } - - //return our result - return res; - } - - float ReadAxis(const InputMapped& im) - { - assert(im.index < g_pJoysticks.size()); - if (im.index >= g_pJoysticks.size()) - return 0; - - LONG value = 0; - if (im.type == MT_AXIS) - value = g_pJoysticks[im.index]->GetAxis(im.mapped); - else if (im.type == MT_BUTTON && g_pJoysticks[im.index]->GetButton(im.mapped)) // for the lulz - { - value = USHRT_MAX; - } - - - float retval = 0; - - if (im.HALF > 60000) // origin somewhere near top - { - retval = (65535 - value) * (1.0f / 65535); - } - else if (im.HALF > 26000 && im.HALF < 38000) // origin somewhere near center - { - if (im.INVERTED) - retval = (value - 32767) * (1.0f / 32767); - else - retval = (32767 - value) * (1.0f / 32767); - } - else if (im.HALF >= 0 && im.HALF < 4000) // origin somewhere near bottom - { - retval = value * (1.0f / 65535); - } - - if (retval < 0.0f) - retval = 0.0f; - - return retval; - } - - float ReadAxis(int port, int cid) - { - InputMapped im; - if (!GetInputMap(port, cid, im)) - return 0; - return ReadAxis(im); - } - - //using both above functions - float ReadAxisFiltered(int port, int cid) - { - InputMapped im; - if (!GetInputMap(port, cid, im)) - return 0; - return FilterControl(ReadAxis(im), im.LINEAR, im.OFFSET, im.DEADZONE); - } - - void AutoCenter(LPDIRECTINPUTDEVICE8 device, bool onoff) - { - if (!device) - return; - //disable the auto-centering spring. - DIPROPDWORD dipdw { sizeof(dipdw), sizeof(dipdw.diph) }; - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = onoff ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF; - - device->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph); - } - - void SetRamp(int port, const ramp& var) - { - } - - void SetRampVariable(int port, int forceids, const variable& var) - { - if (!FFB[port]) - return; - - // one main loop is 2ms, too erratic - effRamp.dwDuration = 2000 * (var.t1 + 1) * 25; - - // Force0 only (Force2 is Y axis?) - if (forceids & 1) - { - int force = var.l1; - int dir = (var.d1 & 1 ? 1 : -1); - - if (INVERTFORCES[port]) - { - cRamp.lStart = (127 - force) * DI_FFNOMINALMAX / 127; - int sign = 1; - if (cRamp.lStart < 0) - sign = -1; // pull to force's direction? - cRamp.lEnd = sign * DI_FFNOMINALMAX * dir; - } - else - { - cRamp.lStart = -(127 - force) * DI_FFNOMINALMAX / 127; - //int sign = -1; - //if (cRamp.lStart < 0) sign = 1; // pull to force's direction? - //cRamp.lEnd = sign * DI_FFNOMINALMAX * dir; // or to center? - cRamp.lEnd = -(127 - (force + /* var.t1 **/ var.s1 * dir)) * DI_FFNOMINALMAX / 127; - } - } - - if (g_pEffectRamp[port]) - g_pEffectRamp[port]->SetParameters(&effRamp, - DIEP_TYPESPECIFICPARAMS | DIEP_START | DIEP_DURATION); - } - - void DisableRamp(int port) - { - if (g_pEffectRamp[port]) - g_pEffectRamp[port]->Stop(); - } - - // IDK - void SetSpringSlopeForce(int port, const spring& spring) - { - cSpring.lOffset = 0; - cSpring.lNegativeCoefficient = (spring.s1 & 1 ? -1 : 1) * spring.k1 * 10000 / 15; - cSpring.lPositiveCoefficient = (spring.s2 & 1 ? -1 : 1) * spring.k2 * 10000 / 15; - cSpring.dwNegativeSaturation = spring.dead1 * 10000 / 0xFF; - cSpring.dwPositiveSaturation = spring.dead2 * 10000 / 0xFF; - cSpring.lDeadBand = 0; - - if (g_pEffectSpring[port]) - g_pEffectSpring[port]->SetParameters(&effSpring, DIEP_TYPESPECIFICPARAMS | DIEP_START); - } - - void JoystickDeviceFF::SetConstantForce(int level) - { - - //FIXME either this or usb-pad-ff was inverted - if (INVERTFORCES[m_port]) - cfw.lMagnitude = -level * DI_FFNOMINALMAX / SHRT_MAX; - else - cfw.lMagnitude = level * DI_FFNOMINALMAX / SHRT_MAX; - - if (FFMULTI[m_port][0] > 0) - cfw.lMagnitude *= 1 + FFMULTI[m_port][0]; - - if (g_pEffectConstant[m_port]) - { - g_pEffectConstant[m_port]->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START); - - //DWORD flags; - //g_pEffectConstant->GetEffectStatus(&flags); - - //if(!(flags & DIEGES_PLAYING)) - //{ - // InitDI(); - //} - } - } - - void JoystickDeviceFF::SetSpringForce(const parsed_ff_data& ff) - { - cSpring.dwNegativeSaturation = ff.u.condition.left_saturation * DI_FFNOMINALMAX / SHRT_MAX; - cSpring.dwPositiveSaturation = ff.u.condition.right_saturation * DI_FFNOMINALMAX / SHRT_MAX; - - cSpring.lNegativeCoefficient = ff.u.condition.left_coeff * DI_FFNOMINALMAX / SHRT_MAX; - cSpring.lPositiveCoefficient = ff.u.condition.right_coeff * DI_FFNOMINALMAX / SHRT_MAX; - - cSpring.lOffset = ff.u.condition.center * DI_FFNOMINALMAX / SHRT_MAX; - cSpring.lDeadBand = ff.u.condition.deadband * DI_FFNOMINALMAX / USHRT_MAX; - - if (g_pEffectSpring[m_port]) - g_pEffectSpring[m_port]->SetParameters(&effSpring, DIEP_TYPESPECIFICPARAMS | DIEP_START); - } - - void JoystickDeviceFF::SetDamperForce(const parsed_ff_data& ff) - { - cDamper.dwNegativeSaturation = ff.u.condition.left_saturation * DI_FFNOMINALMAX / SHRT_MAX; - cDamper.dwPositiveSaturation = ff.u.condition.right_saturation * DI_FFNOMINALMAX / SHRT_MAX; - - cDamper.lNegativeCoefficient = ff.u.condition.left_coeff * DI_FFNOMINALMAX / SHRT_MAX; - cDamper.lPositiveCoefficient = ff.u.condition.right_coeff * DI_FFNOMINALMAX / SHRT_MAX; - - cDamper.lOffset = ff.u.condition.center * DI_FFNOMINALMAX / SHRT_MAX; - cDamper.lDeadBand = ff.u.condition.deadband * DI_FFNOMINALMAX / USHRT_MAX; - - if (g_pEffectDamper[m_port]) - g_pEffectDamper[m_port]->SetParameters(&effDamper, DIEP_TYPESPECIFICPARAMS | DIEP_START); - } - - //LG driver converts it into high-precision damper instead, hmm - void JoystickDeviceFF::SetFrictionForce(const parsed_ff_data& ff) - { - cFriction.dwNegativeSaturation = ff.u.condition.left_saturation * DI_FFNOMINALMAX / SHRT_MAX; - cFriction.dwPositiveSaturation = ff.u.condition.right_saturation * DI_FFNOMINALMAX / SHRT_MAX; - - cFriction.lNegativeCoefficient = ff.u.condition.left_coeff * DI_FFNOMINALMAX / SHRT_MAX; - cFriction.lPositiveCoefficient = ff.u.condition.right_coeff * DI_FFNOMINALMAX / SHRT_MAX; - - cFriction.lOffset = ff.u.condition.center * DI_FFNOMINALMAX / SHRT_MAX; - cFriction.lDeadBand = ff.u.condition.deadband * DI_FFNOMINALMAX / USHRT_MAX; - - if (g_pEffectFriction[m_port]) - g_pEffectFriction[m_port]->SetParameters(&effFriction, DIEP_TYPESPECIFICPARAMS | DIEP_START); - } - - void JoystickDeviceFF::DisableForce(EffectID force) - { - switch (force) - { - case EFF_CONSTANT: - if (g_pEffectConstant[m_port]) - g_pEffectConstant[m_port]->Stop(); - break; - case EFF_SPRING: - if (g_pEffectSpring[m_port]) - g_pEffectSpring[m_port]->Stop(); - break; - case EFF_DAMPER: - if (g_pEffectDamper[m_port]) - g_pEffectDamper[m_port]->Stop(); - break; - case EFF_FRICTION: - if (g_pEffectFriction[m_port]) - g_pEffectFriction[m_port]->Stop(); - break; - case EFF_RUMBLE: - break; - } - } - - void JoystickDeviceFF::SetAutoCenter(int value) - { - InputMapped im; - LPDIRECTINPUTDEVICE8 dev = nullptr; - if (GetInputMap(m_port, CID_STEERING, im)) - dev = g_pJoysticks[im.index]->GetDevice(); - - AutoCenter(dev, value > 0); - } - - void FreeDirectInput() - { - if (!refCount || --refCount > 0) - return; - - ReleaseFFB(0); - ReleaseFFB(1); - - // Release any DirectInput objects. - for (auto joy : g_pJoysticks) - delete joy; - g_pJoysticks.clear(); - - SAFE_RELEASE(g_pDI); - didDIinit = false; - } - - //initialize all available devices - HRESULT InitDirectInput(HWND hWindow, int port) - { - - HRESULT hr; - LPDIRECTINPUTDEVICE8 pKeyboard = NULL; - LPDIRECTINPUTDEVICE8 pMouse = NULL; - - //release any previous resources - - if (refCount == 0) - { - // Create a DInput object - if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, - IID_IDirectInput8, (VOID**)&g_pDI, NULL))) - return hr; - - //Create Keyboard - g_pDI->CreateDevice(GUID_SysKeyboard, &pKeyboard, NULL); - if (pKeyboard) - { - pKeyboard->SetDataFormat(&c_dfDIKeyboard); - pKeyboard->SetCooperativeLevel(hWindow, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); - pKeyboard->Acquire(); - g_pJoysticks.push_back(new JoystickDevice(CT_KEYBOARD, pKeyboard, GUID_SysKeyboard, TEXT("SysKeyboard"))); - } - - //Create Mouse - g_pDI->CreateDevice(GUID_SysMouse, &pMouse, NULL); - if (pMouse) - { - pMouse->SetDataFormat(&c_dfDIMouse2); - pMouse->SetCooperativeLevel(hWindow, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); - pMouse->Acquire(); - g_pJoysticks.push_back(new JoystickDevice(CT_MOUSE, pMouse, GUID_SysMouse, TEXT("SysMouse"))); - } - - //enumerate attached only - g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY); - - //loop through all attached joysticks - for (size_t i = 0; i < g_pJoysticks.size(); i++) - { - auto joy = g_pJoysticks[i]; - auto device = joy->GetDevice(); - device->SetDataFormat(&c_dfDIJoystick2); - - DIDEVCAPS diCaps { sizeof(diCaps) }; - device->GetCapabilities(&diCaps); - - if (diCaps.dwFlags & DIDC_FORCEFEEDBACK) - { - //Exclusive - device->SetCooperativeLevel(hWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND); - - /*DIDEVICEINSTANCE instance_; - ZeroMemory(&instance_, sizeof(DIDEVICEINSTANCE)); - instance_.dwSize = sizeof(DIDEVICEINSTANCE); - g_pJoysticks[i]->GetDeviceInfo(&instance_); - std::stringstream str; - str << instance_.guidInstance;*/ - } - else - device->SetCooperativeLevel(hWindow, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); - - device->EnumObjects(EnumObjectsCallback, device, DIDFT_ALL); - device->Acquire(); - } - } - - ++refCount; - - didDIinit = true; - return S_OK; - } - - HWND GetWindowHandle(DWORD tPID) - { - //Get first window handle - HWND res = FindWindow(NULL, NULL); - DWORD mPID = 0; - while (res != 0) - { - if (!GetParent(res)) - { - GetWindowThreadProcessId(res, &mPID); - if (mPID == tPID) - return res; - } - res = GetWindow(res, GW_HWNDNEXT); - } - return NULL; - } - - bool FindFFDevice(int port) - { - InputMapped im; - if (!GetInputMap(port, CID_STEERING, im)) - return false; - - auto device = g_pJoysticks[im.index]->GetDevice(); - DIDEVCAPS diCaps { sizeof(diCaps) }; - device->GetCapabilities(&diCaps); - - //has ffb? - if (!FFB[port] && (diCaps.dwFlags & DIDC_FORCEFEEDBACK)) - { - - //FIXME im.mapped is offset to GetAxisValueFromOffset, compatibility with DIEFFECT::rgdwAxes is questionable after DIJOYSTATE2::rglSlider - CreateFFB(port, device, im.mapped); - - AutoCenter(device, false); //TODO some games set autocenter. Figure out default for ones that don't. - - /*DIDEVICEINSTANCE instance_; - ZeroMemory(&instance_, sizeof(DIDEVICEINSTANCE)); - instance_.dwSize = sizeof(DIDEVICEINSTANCE); - g_pJoysticks[i]->GetDeviceInfo(&instance_); - std::stringstream str; - str << instance_.guidInstance;*/ - } - return FFB[port]; - } - - //use direct input - void InitDI(int port, const char* dev_type) - { - HWND hWin = nullptr; - - if (gsWnd) - { - hWin = gsWnd; - } - else - { - pid = GetCurrentProcessId(); - while (hWin == 0) - { - hWin = GetWindowHandle(pid); - } - } - - // DirectInput needs a top-level window - InitDirectInput(GetAncestor(hWin, GA_ROOT), port); - LoadDInputConfig(port, dev_type); - FindFFDevice(port); - } - - bool GetControl(int port, int id) - { - InputMapped im; - if (!GetInputMap(port, id, im)) - return false; - - assert(im.index < g_pJoysticks.size()); - if (im.index >= g_pJoysticks.size()) - return false; - - auto joy = g_pJoysticks[im.index]; - - if (im.type == MT_AXIS) - { - return ReadAxisFiltered(port, id) >= 0.5f; - } - else if (im.type == MT_BUTTON) - { - return joy->GetButton(im.mapped); - } - return false; - } - - float GetAxisControl(int port, ControlID id) - { - if (id == CID_STEERING) - { - //apply steering, single axis is split to two for filtering - if (ReadAxisFiltered(port, CID_STEERING) > 0.0) - { - return -ReadAxisFiltered(port, CID_STEERING); - } - else - { - if (ReadAxisFiltered(port, CID_STEERING_R) > 0.0) - { - return ReadAxisFiltered(port, CID_STEERING_R); - } - else - { - return 0; - } - } - } - - return ReadAxisFiltered(port, id); - } - - int32_t GetAxisControlUnfiltered(int port, ControlID id) - { - InputMapped im; - if (!GetInputMap(port, id, im)) - return 0; - - assert(im.index < g_pJoysticks.size()); - if (im.index >= g_pJoysticks.size()) - return 0; - - LONG value = 0; - if (im.type == MT_AXIS) - { - value = g_pJoysticks[im.index]->GetAxis(im.mapped); - } - return value; - } - - //set left/right ffb torque - HRESULT SetConstantForce(int port, LONG magnitude) - { - if (!FFB[port] || !g_pEffectConstant[port]) - return DIERR_NOTINITIALIZED; - - if (INVERTFORCES[port]) - cfw.lMagnitude = -magnitude; - else - cfw.lMagnitude = magnitude; - - if (FFMULTI[port][0] > 0) - cfw.lMagnitude *= 1 + FFMULTI[port][0]; - - return g_pEffectConstant[port]->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START); - } - - bool StartTestForce(int port) - { - InputMapped im; - LPDIRECTINPUTDEVICE8 dev = nullptr; - if (GetInputMap(port, CID_STEERING, im)) - dev = g_pJoysticks[im.index]->GetDevice(); - - // Gain value may have changed, so update it for the constant force effect - return UpdateFFBSettings(port, dev); - } - - bool UpdateTestForce(int port, unsigned int stage) - { - // FFB test ticks every 500ms and goes as follows: - // Turn right, wait 500ms, turn left, wait 1000ms, turn right, wait 500ms, end - if (stage == 0) - { - return SUCCEEDED(SetConstantForce(port, DI_FFNOMINALMAX / 3)); - } - if (stage == 1) - { - return SUCCEEDED(SetConstantForce(port, -DI_FFNOMINALMAX / 3)); - } - if (stage == 2) - { - // Do nothing, as we wait 1000ms - return true; - } - if (stage == 3) - { - return SUCCEEDED(SetConstantForce(port, DI_FFNOMINALMAX / 3)); - } - return false; - } - - bool EndTestForce(int port) - { - return SUCCEEDED(SetConstantForce(port, 0)); - } - - } // namespace dx -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/dx/dx.h b/pcsx2/USB/usb-pad/dx/dx.h deleted file mode 100644 index 138fc94861..0000000000 --- a/pcsx2/USB/usb-pad/dx/dx.h +++ /dev/null @@ -1,231 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "USB/usb-pad/usb-pad.h" -#include "USB/configuration.h" -#include "USB/usb-pad/lg/lg_ff.h" - -#define DINPUT_AXES_COUNT 32 - -namespace usb_pad -{ - namespace dx - { - //dinput control mappings - - static const DWORD PRECMULTI = 100; //floating point precision multiplier, 100 - two digit precision after comma - - extern int32_t GAINZ[2][1]; - extern int32_t FFMULTI[2][1]; - extern int32_t INVERTFORCES[2]; - - static bool didDIinit = false; //we have a handle - - std::ostream& operator<<(std::ostream& os, REFGUID guid); - - enum ControlID - { - CID_STEERING, - CID_STEERING_R, - CID_THROTTLE, - CID_BRAKE, - CID_HATUP, - CID_HATDOWN, - CID_HATLEFT, - CID_HATRIGHT, - CID_SQUARE, - CID_TRIANGLE, - CID_CROSS, - CID_CIRCLE, - CID_L1, - CID_R1, - CID_L2, - CID_R2, - CID_L3, - CID_R3, - CID_SELECT, - CID_START, - CID_BUTTON20, - CID_BUTTON21, - CID_BUTTON22, - CID_BUTTON23, - CID_BUTTON24, - CID_BUTTON25, - CID_BUTTON26, - CID_BUTTON27, - CID_BUTTON28, - CID_BUTTON29, - CID_BUTTON30, - CID_COUNT, - }; - - // Maybe merge with JoystickDevice - class JoystickDeviceFF : public FFDevice - { - public: - JoystickDeviceFF(int port) - : m_port(port) - { - } - ~JoystickDeviceFF() {} - - void SetConstantForce(int level); - void SetSpringForce(const parsed_ff_data& ff); - void SetDamperForce(const parsed_ff_data& ff); - void SetFrictionForce(const parsed_ff_data& ff); - void SetAutoCenter(int value); - void DisableForce(EffectID force); - - private: - int m_port; - }; - - enum ControlType - { - CT_NONE, - CT_KEYBOARD, - CT_MOUSE, - CT_JOYSTICK, - }; - - enum MappingType - { - MT_NONE = 0, //TODO leave for sanity checking? - MT_AXIS, - MT_BUTTON, - }; - - struct InputMapped - { - size_t index; //index into g_pJoysticks - MappingType type = MT_NONE; - int32_t mapped; //device axis/button - bool INVERTED; - int32_t HALF; - int32_t LINEAR; - int32_t OFFSET; - int32_t DEADZONE; - }; - - class JoystickDevice - { - public: - JoystickDevice(ControlType type, LPDIRECTINPUTDEVICE8 device, GUID guid, TSTDSTRING name) - : m_type(type) - , m_guid(guid) - , m_device(device) - , m_product(name) - { - } - - bool Poll(); - - /*void GetDeviceState(size_t sz, void *ptr) - { - if (sz == sizeof(DIJOYSTATE2) && ptr) - *ptr = m_jstate; - }*/ - - DIJOYSTATE2 GetDeviceState() - { - //assert(m_type == CT_JOYSTICK); - return m_controls.js2; - } - - HRESULT GetDeviceState(DWORD sz, LPVOID ptr) - { - return m_device->GetDeviceState(sz, ptr); - } - - bool GetButton(int b); - LONG GetAxis(int a); - - LPDIRECTINPUTDEVICE8 GetDevice() - { - return m_device; - } - - GUID GetGUID() - { - return m_guid; - } - - const TSTDSTRING& Product() const - { - return m_product; - } - - ControlType GetControlType() { return m_type; } - - ~JoystickDevice(); - - private: - GUID m_guid; - TSTDSTRING m_product; - LPDIRECTINPUTDEVICE8 m_device; - ControlType m_type = CT_NONE; - union - { - DIJOYSTATE2 js2; - DIMOUSESTATE2 ms2; - BYTE kbd[256]; - } m_controls = {}; - }; - - extern std::vector g_pJoysticks; - extern std::map g_Controls[2]; - - void ApplySettings(int port); - void LoadDInputConfig(int port, const char* dev_type); - void SaveDInputConfig(int port, const char* dev_type); - - void InitDI(int port, const char* dev_type); - HRESULT InitDirectInput(HWND hWindow, int port); - void FreeDirectInput(); - void PollDevices(); - float ReadAxis(const InputMapped& im); - float ReadAxis(int port, int axisid); - float FilterControl(float input, LONG linear, LONG offset, LONG dead); - - bool StartTestForce(int port); - bool UpdateTestForce(int port, unsigned int stage); - bool EndTestForce(int port); - - LONG GetAxisValueFromOffset(int axis, const DIJOYSTATE2& j); - bool GetControl(int port, int id); - float GetAxisControl(int port, ControlID id); - int32_t GetAxisControlUnfiltered(int port, ControlID id); - void CreateFFB(int port, LPDIRECTINPUTDEVICE8 device, DWORD axis); - bool FindFFDevice(int port); - bool UpdateFFBSettings(int port, LPDIRECTINPUTDEVICE8 device); - - void AddInputMap(int port, int cid, const InputMapped& im); - void RemoveInputMap(int port, int cid); - bool GetInputMap(int port, int cid, InputMapped& im); - - } // namespace dx -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/dx/usb-pad-dx.cpp b/pcsx2/USB/usb-pad/dx/usb-pad-dx.cpp deleted file mode 100644 index e53f2f3575..0000000000 --- a/pcsx2/USB/usb-pad/dx/usb-pad-dx.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "usb-pad-dx.h" -#include "dx.h" -#include - -namespace usb_pad -{ - namespace dx - { - - static bool bdown = false; - static DWORD calibrationtime = 0; - static int calidata = 0; - static bool alternate = false; - static bool calibrating = false; - - DInputPad::~DInputPad() { FreeDirectInput(); } - - int DInputPad::TokenIn(uint8_t* buf, int len) - { - int range = range_max(mType); - - // Setting to unpressed - ZeroMemory(&mWheelData, sizeof(wheel_data_t)); - mWheelData.steering = range >> 1; - mWheelData.clutch = 0xFF; - mWheelData.throttle = 0xFF; - mWheelData.brake = 0xFF; - mWheelData.hatswitch = 0x8; - - PollDevices(); - - if (mType == WT_BUZZ_CONTROLLER) - { - for (int i = 0; i < 20; i++) - { - if (GetControl(mPort, i)) - { - mWheelData.buttons |= 1 << i; - } - } - pad_copy_data(mType, buf, mWheelData); - return 5; - } - else if (mType == WT_GAMETRAK_CONTROLLER) - { - mWheelData.buttons |= GetControl(mPort, CID_HATLEFT) << 4; - mWheelData.clutch = GetAxisControlUnfiltered(mPort, CID_STEERING) >> 4; - mWheelData.throttle = GetAxisControlUnfiltered(mPort, CID_STEERING_R) >> 4; - mWheelData.brake = GetAxisControlUnfiltered(mPort, CID_THROTTLE) >> 4; - mWheelData.hatswitch = GetAxisControlUnfiltered(mPort, CID_BRAKE) >> 4; - mWheelData.hat_horz = GetAxisControlUnfiltered(mPort, CID_HATUP) >> 4; - mWheelData.hat_vert = GetAxisControlUnfiltered(mPort, CID_HATDOWN) >> 4; - pad_copy_data(mType, buf, mWheelData); - return 16; - } - else if (mType >= WT_REALPLAY_RACING && mType <= WT_REALPLAY_POOL) - { - for (int i = 0; i < 8; i++) - { - if (GetControl(mPort, i)) - { - mWheelData.buttons |= 1 << i; - } - } - mWheelData.clutch = GetAxisControlUnfiltered(mPort, CID_SQUARE) >> 4; - mWheelData.throttle = GetAxisControlUnfiltered(mPort, CID_TRIANGLE) >> 4; - mWheelData.brake = GetAxisControlUnfiltered(mPort, CID_CROSS) >> 4; - pad_copy_data(mType, buf, mWheelData); - return 19; - } - else if (mType == WT_KEYBOARDMANIA_CONTROLLER) - { - for (int i = 0; i < 31; i++) - { - if (GetControl(mPort, i)) - { - mWheelData.buttons |= 1 << i; - } - } - pad_copy_data(mType, buf, mWheelData); - return len; - } - - //Allow in both ports but warn in configure dialog that only one DX wheel is supported for now - //if(idx == 0){ - //mWheelData.steering = 8191 + (int)(GetControl(STEERING, false)* 8191.0f) ; - - if (calibrating) - { - //Alternate full extents - if (alternate) - calidata--; - else - calidata++; - - if (calidata > range - 1 || calidata < 1) - alternate = !alternate; //invert - - mWheelData.steering = calidata; //pass fake - - //breakout after 11 seconds - if (GetTickCount() - calibrationtime > 11000) - { - calibrating = false; - mWheelData.steering = range >> 1; - } - } - else - { - mWheelData.steering = (range >> 1) + std::lround(GetAxisControl(mPort, CID_STEERING) * (float)(range >> 1)); - } - - mWheelData.throttle = std::lround(255.f - (GetAxisControl(mPort, CID_THROTTLE) * 255.0f)); - mWheelData.brake = std::lround(255.f - (GetAxisControl(mPort, CID_BRAKE) * 255.0f)); - - if (GetControl(mPort, CID_CROSS)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_CROSS); - if (GetControl(mPort, CID_SQUARE)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_SQUARE); - if (GetControl(mPort, CID_CIRCLE)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_CIRCLE); - if (GetControl(mPort, CID_TRIANGLE)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_TRIANGLE); - if (GetControl(mPort, CID_R1)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R1); - if (GetControl(mPort, CID_L1)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L1); - if (GetControl(mPort, CID_R2)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R2); - if (GetControl(mPort, CID_L2)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L2); - - if (GetControl(mPort, CID_SELECT)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_SELECT); - if (GetControl(mPort, CID_START)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_START); - if (GetControl(mPort, CID_R3)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R3); - if (GetControl(mPort, CID_L3)) - mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L3); - - //diagonal - if (GetControl(mPort, CID_HATUP) && GetControl(mPort, CID_HATRIGHT)) - mWheelData.hatswitch = 1; - if (GetControl(mPort, CID_HATRIGHT) && GetControl(mPort, CID_HATDOWN)) - mWheelData.hatswitch = 3; - if (GetControl(mPort, CID_HATDOWN) && GetControl(mPort, CID_HATLEFT)) - mWheelData.hatswitch = 5; - if (GetControl(mPort, CID_HATLEFT) && GetControl(mPort, CID_HATUP)) - mWheelData.hatswitch = 7; - - //regular - if (mWheelData.hatswitch == 0x8) - { - if (GetControl(mPort, CID_HATUP)) - mWheelData.hatswitch = 0; - if (GetControl(mPort, CID_HATRIGHT)) - mWheelData.hatswitch = 2; - if (GetControl(mPort, CID_HATDOWN)) - mWheelData.hatswitch = 4; - if (GetControl(mPort, CID_HATLEFT)) - mWheelData.hatswitch = 6; - } - - pad_copy_data(mType, buf, mWheelData); - //} //if(idx ... - return len; - } - - int DInputPad::TokenOut(const uint8_t* data, int len) - { - const ff_data* ffdata = (const ff_data*)data; - bool hires = (mType == WT_DRIVING_FORCE_PRO || mType == WT_DRIVING_FORCE_PRO_1102); - ParseFFData(ffdata, hires); - - return len; - } - - int DInputPad::Open() - { - LoadSetting(mDevType, mPort, APINAME, TEXT("UseRamp"), mUseRamp); - InitDI(mPort, mDevType); - if (!mFFdev) - mFFdev = new JoystickDeviceFF(mPort /*, mUseRamp*/); - return 0; - } - - int DInputPad::Close() - { - FreeDirectInput(); - return 0; - } - - } // namespace dx -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/dx/usb-pad-dx.h b/pcsx2/USB/usb-pad/dx/usb-pad-dx.h deleted file mode 100644 index ecf1821134..0000000000 --- a/pcsx2/USB/usb-pad/dx/usb-pad-dx.h +++ /dev/null @@ -1,53 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "USB/usb-pad/padproxy.h" -#include "USB/Win32/Config_usb.h" - -namespace usb_pad -{ - namespace dx - { - - static const char* APINAME = "dinput"; - - class DInputPad : public Pad - { - public: - DInputPad(int port, const char* dev_type) - : Pad(port, dev_type) - , mUseRamp(0) - { - } - ~DInputPad(); - int Open(); - int Close(); - int TokenIn(uint8_t* buf, int len); - int TokenOut(const uint8_t* data, int len); - int Reset() { return 0; } - - static const TCHAR* Name() - { - return TEXT("DInput"); - } - - static int Configure(int port, const char* dev_type, void* data); - - private: - int32_t mUseRamp; - }; - - } // namespace dx -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/dx/versionproxy.h b/pcsx2/USB/usb-pad/dx/versionproxy.h deleted file mode 100644 index 412ef1f1d3..0000000000 --- a/pcsx2/USB/usb-pad/dx/versionproxy.h +++ /dev/null @@ -1,204 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by versionproxy.rc -// -#define IDC_STATIC -1 -#define IDOK2 2 -#define IDD_DLG_BUZZ 114 -#define IDD_DLG_KEYBOARDMANIA 115 -#define IDD_DLG_GAMETRAK 116 -#define IDD_DLG_REALPLAY 120 -#define IDD_DIALOG1 202 -#define IDC_DEL0 1001 -#define IDC_ASS0 1002 -#define IDC_DEL1 1003 -#define IDC_ASS1 1004 -#define IDC_DEL2 1005 -#define IDC_ASS2 1006 -#define IDC_DEL3 1007 -#define IDC_ASS3 1008 -#define IDC_DEL4 1009 -#define IDC_ASS4 1010 -#define IDC_DEL5 1011 -#define IDC_ASS5 1012 -#define IDC_COMBO4 1013 -#define IDC_LABEL0 1014 -#define IDC_BUTTON13 1015 -#define IDC_DEL8 1015 -#define IDC_BUTTON14 1016 -#define IDC_ASS8 1016 -#define IDC_BUTTON15 1017 -#define IDC_DEL9 1017 -#define IDC_BUTTON16 1018 -#define IDC_ASS9 1018 -#define IDC_BUTTON17 1019 -#define IDC_DEL10 1019 -#define IDC_BUTTON18 1020 -#define IDC_ASS10 1020 -#define IDC_BUTTON19 1021 -#define IDC_DEL11 1021 -#define IDC_BUTTON20 1022 -#define IDC_ASS11 1022 -#define IDC_BUTTON21 1023 -#define IDC_DEL12 1023 -#define IDC_BUTTON22 1024 -#define IDC_ASS12 1024 -#define IDC_BUTTON23 1025 -#define IDC_DEL13 1025 -#define IDC_BUTTON24 1026 -#define IDC_ASS13 1026 -#define IDC_BUTTON25 1027 -#define IDC_DEL14 1027 -#define IDC_BUTTON26 1028 -#define IDC_ASS14 1028 -#define IDC_BUTTON27 1029 -#define IDC_DEL6 1029 -#define IDC_BUTTON28 1030 -#define IDC_ASS6 1030 -#define IDC_BUTTON29 1031 -#define IDC_DEL7 1031 -#define IDC_BUTTON30 1032 -#define IDC_ASS7 1032 -#define IDC_LABEL1 1033 -#define IDC_LABEL2 1034 -#define IDC_LABEL3 1035 -#define IDC_LABEL4 1036 -#define IDC_LABEL5 1037 -#define IDC_LABEL6 1038 -#define IDC_LABEL7 1039 -#define IDC_LABEL8 1040 -#define IDC_LABEL9 1041 -#define IDC_LABEL10 1042 -#define IDC_LABEL11 1043 -#define IDC_LABEL12 1044 -#define IDC_LABEL13 1045 -#define IDC_LABEL14 1046 -#define IDC_LABEL15 1047 -#define IDC_EDIT1 1048 -#define IDC_DEL15 1048 -#define IDC_ASS15 1049 -#define IDC_LABEL16 1050 -#define IDC_DEL16 1051 -#define IDC_ASS16 1052 -#define IDC_GROUP1 1053 -#define IDC_GROUP2 1054 -#define IDC_GROUP3 1055 -#define IDC_EDIT4 1056 -#define IDC_EDIT5 1057 -#define IDC_PICTURE 1058 -#define IDC_SLIDER1 1059 -#define IDC_SLIDER2 1060 -#define IDC_COMBO1 1061 -#define IDC_COMBO2 1062 -#define IDC_SLIDER3 1062 -#define IDC_COMBO3 1063 -#define IDC_ASS17 1064 -#define IDC_LINEAR 1065 -#define IDC_OFFSET 1066 -#define IDC_LABEL18 1067 -#define IDC_GROUP4 1068 -#define IDC_GROUP5 1069 -#define IDC_GROUP6 1070 -#define IDC_GROUP7 1071 -#define IDC_GROUP8 1072 -#define IDC_GROUP9 1073 -#define IDC_GROUP10 1074 -#define IDC_GROUP11 1075 -#define IDC_GROUP12 1076 -#define IDC_GROUP13 1077 -#define IDC_GROUP14 1078 -#define IDC_GROUP15 1079 -#define IDC_GROUP16 1080 -#define IDC_GROUP17 1081 -#define IDC_GROUP18 1082 -#define IDC_GROUP19 1083 -#define IDC_GROUP20 1084 -#define IDC_GROUP21 1085 -#define IDC_DEADZONE 1086 -#define IDC_GROUP22 1087 -#define IDC_CHECK5 1088 -#define IDC_GROUP24 1088 -#define IDC_CHECK6 1089 -#define IDC_DEL18 1089 -#define IDC_CHECK7 1090 -#define IDC_ASS18 1090 -#define IDC_GROUP25 1091 -#define IDC_EDIT2 1092 -#define IDC_LABEL19 1092 -#define IDC_CHECK8 1093 -#define IDC_DEL19 1093 -#define IDC_IPADDRESS2 1094 -#define IDC_ASS19 1094 -#define IDC_EDIT3 1095 -#define IDC_CHECK9 1096 -#define IDC_IPADDRESS3 1097 -#define IDC_GROUP23 1098 -#define IDC_CHECK10 1099 -#define IDC_PICTURELINK1 1101 -#define IDC_PICTURELINK2 1102 -#define IDC_PICTURELINK3 1103 -#define IDC_BUTTON31 1105 -#define IDC_TEXT 1106 -#define IDC_LABEL17 1107 -#define IDC_GROUP26 1108 -#define IDC_DEL17 1109 -#define IDC_BUTTON1 1110 -#define IDC_CHECK1 1111 -#define IDC_CHECK3 1113 -#define IDC_SLIDER4 1114 -#define IDC_BUTTON3 1116 -#define IDC_SLIDER5 1117 -#define IDC_BZ_CTL1_LBL1 1118 -#define IDC_BZ_CTL1_LBL2 1119 -#define IDC_BZ_CTL1_LBL3 1120 -#define IDC_BZ_CTL1_LBL4 1121 -#define IDC_BZ_CTL1_LBL5 1122 -#define IDC_BZ_CTL2_LBL1 1123 -#define IDC_BZ_CTL2_LBL2 1124 -#define IDC_BZ_CTL2_LBL3 1125 -#define IDC_BZ_CTL2_LBL4 1126 -#define IDC_BZ_CTL2_LBL5 1127 -#define IDC_BZ_CTL3_LBL1 1128 -#define IDC_BZ_CTL3_LBL2 1129 -#define IDC_BZ_CTL3_LBL3 1130 -#define IDC_BZ_CTL3_LBL4 1131 -#define IDC_BZ_CTL3_LBL5 1132 -#define IDC_BZ_CTL4_LBL1 1133 -#define IDC_BZ_CTL4_LBL2 1134 -#define IDC_BZ_CTL4_LBL3 1135 -#define IDC_BZ_CTL4_LBL4 1136 -#define IDC_BZ_CTL4_LBL5 1137 -#define IDC_LABEL20 1138 -#define IDC_ASS20 1139 -#define IDC_LABEL21 1140 -#define IDC_ASS21 1141 -#define IDC_LABEL22 1142 -#define IDC_ASS22 1143 -#define IDC_LABEL23 1144 -#define IDC_ASS23 1145 -#define IDC_LABEL24 1146 -#define IDC_ASS24 1147 -#define IDC_LABEL25 1148 -#define IDC_ASS25 1149 -#define IDC_LABEL26 1150 -#define IDC_ASS26 1151 -#define IDC_LABEL27 1152 -#define IDC_ASS27 1153 -#define IDC_LABEL28 1154 -#define IDC_ASS28 1155 -#define IDC_LABEL29 1156 -#define IDC_ASS29 1157 -#define IDC_LABEL30 1158 -#define IDC_ASS30 1159 -#define IDC_DELALL 1160 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 121 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1137 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/pcsx2/USB/usb-pad/dx/versionproxy.rc b/pcsx2/USB/usb-pad/dx/versionproxy.rc deleted file mode 100644 index 2f9cfc4296..0000000000 --- a/pcsx2/USB/usb-pad/dx/versionproxy.rc +++ /dev/null @@ -1,464 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "versionproxy.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winresrc.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "versionproxy.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""WinResrc.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_DIALOG1 DIALOGEX 0, 0, 670, 309 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CTEXT "AXIS",IDC_GROUP1,6,6,186,12 - GROUPBOX "STEER LEFT",IDC_GROUP4,6,18,186,36 - LTEXT "1/1/1/1",IDC_LABEL0,12,42,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS0,78,30,54,18 - PUSHBUTTON "DELETE",IDC_DEL0,132,30,54,18 - GROUPBOX "STEER RIGHT",IDC_GROUP5,6,54,186,36 - LTEXT "1/1/1/1",IDC_LABEL1,12,78,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS1,78,66,54,18 - PUSHBUTTON "DELETE",IDC_DEL1,132,66,54,18 - GROUPBOX "THROTTLE",IDC_GROUP6,6,90,186,36 - LTEXT "1/1/1/1",IDC_LABEL2,12,114,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS2,78,102,54,18 - PUSHBUTTON "DELETE",IDC_DEL2,132,102,54,18 - GROUPBOX "BRAKE",IDC_GROUP7,6,126,186,36 - LTEXT "1/1/1/1",IDC_LABEL3,12,150,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS3,78,138,54,18 - PUSHBUTTON "DELETE",IDC_DEL3,132,138,54,18 - GROUPBOX "HAT UP",IDC_GROUP8,6,162,186,36 - LTEXT "1/1/1/1",IDC_LABEL4,12,186,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS4,78,174,54,18 - PUSHBUTTON "DELETE",IDC_DEL4,132,174,54,18 - GROUPBOX "HAT DOWN",IDC_GROUP9,6,198,186,36 - LTEXT "1/1/1/1",IDC_LABEL5,12,222,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS5,78,210,54,18 - PUSHBUTTON "DELETE",IDC_DEL5,132,210,54,18 - GROUPBOX "HAT LEFT",IDC_GROUP10,6,234,186,36 - LTEXT "1/1/1/1",IDC_LABEL6,12,258,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS6,78,246,54,18 - PUSHBUTTON "DELETE",IDC_DEL6,132,246,54,18 - GROUPBOX "HAT RIGHT",IDC_GROUP11,6,270,186,36 - LTEXT "1/1/1/1",IDC_LABEL7,12,294,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS7,78,282,54,18 - PUSHBUTTON "DELETE",IDC_DEL7,132,282,54,18 - CTEXT "BUTTON",IDC_GROUP2,198,6,240,12 - GROUPBOX "SQUARE / X / GREEN",IDC_GROUP12,198,18,120,48 - LTEXT "1/1/1/1",IDC_LABEL8,204,54,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS8,204,30,54,18 - PUSHBUTTON "DELETE",IDC_DEL8,258,30,54,18 - GROUPBOX "TRIANGLE / Y / YELLOW",IDC_GROUP13,318,18,120,48 - LTEXT "1/1/1/1",IDC_LABEL9,324,54,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS9,324,30,54,18 - PUSHBUTTON "DELETE",IDC_DEL9,378,30,54,18 - GROUPBOX "CROSS / A / BLUE",IDC_GROUP14,198,66,120,48 - LTEXT "1/1/1/1",IDC_LABEL10,204,102,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS10,204,78,54,18 - PUSHBUTTON "DELETE",IDC_DEL10,258,78,54,18 - GROUPBOX "CIRCLE / B / RED",IDC_GROUP15,318,66,120,48 - LTEXT "1/1/1/1",IDC_LABEL11,324,102,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS11,324,78,54,18 - PUSHBUTTON "DELETE",IDC_DEL11,378,78,54,18 - GROUPBOX "L1 / L",IDC_GROUP16,198,114,120,48 - LTEXT "1/1/1/1",IDC_LABEL12,204,150,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS12,204,126,54,18 - PUSHBUTTON "DELETE",IDC_DEL12,258,126,54,18 - GROUPBOX "R1 / R / ORANGE",IDC_GROUP17,318,114,120,48 - LTEXT "1/1/1/1",IDC_LABEL13,324,150,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS13,324,126,54,18 - PUSHBUTTON "DELETE",IDC_DEL13,378,126,54,18 - GROUPBOX "L2",IDC_GROUP18,198,162,120,48 - LTEXT "1/1/1/1",IDC_LABEL14,204,198,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS14,204,174,54,18 - PUSHBUTTON "DELETE",IDC_DEL14,258,174,54,18 - GROUPBOX "R2",IDC_GROUP19,318,162,120,48 - LTEXT "1/1/1/1",IDC_LABEL15,324,198,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS15,324,174,54,18 - PUSHBUTTON "DELETE",IDC_DEL15,378,174,54,18 - GROUPBOX "L3",IDC_GROUP20,198,210,120,48 - LTEXT "1/1/1/1",IDC_LABEL16,204,246,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS16,204,222,54,18 - PUSHBUTTON "DELETE",IDC_DEL16,258,222,54,18 - GROUPBOX "R3",IDC_GROUP22,318,210,120,48 - LTEXT "1/1/1/1",IDC_LABEL17,324,246,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS17,324,222,54,18 - PUSHBUTTON "DELETE",IDC_DEL17,378,222,54,18 - GROUPBOX "SELECT",IDC_GROUP24,198,258,120,48 - LTEXT "1/1/1/1",IDC_LABEL18,204,294,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS18,204,270,54,18 - PUSHBUTTON "DELETE",IDC_DEL18,258,270,54,18 - GROUPBOX "START",IDC_GROUP25,318,258,120,48 - LTEXT "1/1/1/1",IDC_LABEL19,324,294,66,8 - PUSHBUTTON "REASSIGN",IDC_ASS19,324,270,54,18 - PUSHBUTTON "DELETE",IDC_DEL19,378,270,54,18 - CTEXT "GLOBAL OPTIONS",IDC_GROUP3,444,6,222,12 - GROUPBOX "FILTER/TEST",IDC_GROUP21,444,18,222,150 - COMBOBOX IDC_COMBO1,450,30,114,72,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_PICTURE,"Static",SS_OWNERDRAW | WS_BORDER,450,48,114,96 - LTEXT "LINEARITY",IDC_LINEAR,576,30,78,8 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,570,42,90,24 - LTEXT "OFFSET",IDC_OFFSET,576,72,78,8 - CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,570,84,90,24 - LTEXT "DEAD-ZONE",IDC_DEADZONE,576,114,78,8 - CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,570,126,90,24 - RTEXT "Defaults",IDC_STATIC,450,150,36,12 - COMBOBOX IDC_COMBO3,492,150,72,66,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "FORCE FEEDBACK",IDC_GROUP26,444,168,222,108 - LTEXT "Device",IDC_STATIC,450,180,36,12,NOT WS_VISIBLE,WS_EX_RIGHT - COMBOBOX IDC_COMBO4,492,180,102,51,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "TEST ",IDC_BUTTON1,600,180,30,12 - LTEXT "GAIN",IDC_STATIC,486,204,18,8 - CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,510,198,102,23 - LTEXT "FORCE MULTI",IDC_STATIC,456,228,48,8 - CONTROL "",IDC_SLIDER5,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,510,223,102,23 - CONTROL "INVERT FORCES",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,450,249,65,12 - CONTROL "USE RAMP FOR VARIABLE (0x8) EFFECT",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,519,250,144,12 - PUSHBUTTON "Reset Defaults",IDC_BUTTON3,594,261,60,12,NOT WS_VISIBLE - DEFPUSHBUTTON "OK",IDOK,498,282,80,20 - PUSHBUTTON "Cancel",IDCANCEL,582,282,80,20 -END - -IDD_DLG_BUZZ DIALOGEX 0, 0, 407, 159 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Buzz device" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Controller#1",IDC_STATIC,5,5,99,135 - LTEXT "Red",IDC_BZ_CTL1_LBL1,10,15,38,8 - LTEXT "Blue",IDC_BZ_CTL1_LBL2,10,40,38,8 - LTEXT "Orange",IDC_BZ_CTL1_LBL3,10,65,38,8 - LTEXT "Green",IDC_BZ_CTL1_LBL4,10,90,38,8 - LTEXT "Yellow",IDC_BZ_CTL1_LBL5,10,115,38,8 - LTEXT "1/1/1/1",IDC_LABEL0,10,27,38,8 - LTEXT "1/1/1/1",IDC_LABEL4,10,52,38,8 - LTEXT "1/1/1/1",IDC_LABEL3,10,77,38,8 - LTEXT "1/1/1/1",IDC_LABEL2,10,102,38,8 - LTEXT "1/1/1/1",IDC_LABEL1,10,127,38,8 - PUSHBUTTON "Add",IDC_ASS0,55,15,20,20 - PUSHBUTTON "Del",IDC_DEL0,80,15,20,20 - PUSHBUTTON "Add",IDC_ASS4,55,40,20,20 - PUSHBUTTON "Del",IDC_DEL4,80,40,20,20 - PUSHBUTTON "Add",IDC_ASS3,55,65,20,20 - PUSHBUTTON "Del",IDC_DEL3,80,65,20,20 - PUSHBUTTON "Add",IDC_ASS2,55,90,20,20 - PUSHBUTTON "Del",IDC_DEL2,80,90,20,20 - PUSHBUTTON "Add",IDC_ASS1,55,115,20,20 - PUSHBUTTON "Del",IDC_DEL1,80,115,20,20 - GROUPBOX "Controller#2",IDC_STATIC,105,5,99,135 - LTEXT "Red",IDC_BZ_CTL2_LBL1,110,15,38,8 - LTEXT "Blue",IDC_BZ_CTL2_LBL2,110,40,38,8 - LTEXT "Orange",IDC_BZ_CTL2_LBL3,110,65,38,8 - LTEXT "Green",IDC_BZ_CTL2_LBL4,110,90,38,8 - LTEXT "Yellow",IDC_BZ_CTL2_LBL5,110,115,38,8 - LTEXT "1/1/1/1",IDC_LABEL5,110,27,38,8 - LTEXT "1/1/1/1",IDC_LABEL9,110,52,38,8 - LTEXT "1/1/1/1",IDC_LABEL8,110,77,38,8 - LTEXT "1/1/1/1",IDC_LABEL7,110,102,38,8 - LTEXT "1/1/1/1",IDC_LABEL6,110,127,38,8 - PUSHBUTTON "Add",IDC_ASS5,155,15,20,20 - PUSHBUTTON "Del",IDC_DEL5,180,15,20,20 - PUSHBUTTON "Add",IDC_ASS9,155,40,20,20 - PUSHBUTTON "Del",IDC_DEL9,180,40,20,20 - PUSHBUTTON "Add",IDC_ASS8,155,65,20,20 - PUSHBUTTON "Del",IDC_DEL8,180,65,20,20 - PUSHBUTTON "Add",IDC_ASS7,155,90,20,20 - PUSHBUTTON "Del",IDC_DEL7,180,90,20,20 - PUSHBUTTON "Add",IDC_ASS6,155,115,20,20 - PUSHBUTTON "Del",IDC_DEL6,180,115,20,20 - GROUPBOX "Controller#3",IDC_STATIC,205,5,99,135 - LTEXT "Red",IDC_BZ_CTL3_LBL1,210,15,38,8 - LTEXT "Blue",IDC_BZ_CTL3_LBL2,210,40,38,8 - LTEXT "Orange",IDC_BZ_CTL3_LBL3,210,65,38,8 - LTEXT "Green",IDC_BZ_CTL3_LBL4,210,90,38,8 - LTEXT "Yellow",IDC_BZ_CTL3_LBL5,210,115,38,8 - LTEXT "1/1/1/1",IDC_LABEL10,210,27,38,8 - LTEXT "1/1/1/1",IDC_LABEL14,210,52,38,8 - LTEXT "1/1/1/1",IDC_LABEL13,210,77,38,8 - LTEXT "1/1/1/1",IDC_LABEL12,210,102,38,8 - LTEXT "1/1/1/1",IDC_LABEL11,210,127,38,8 - PUSHBUTTON "Add",IDC_ASS10,255,15,20,20 - PUSHBUTTON "Del",IDC_DEL10,280,15,20,20 - PUSHBUTTON "Add",IDC_ASS14,255,40,20,20 - PUSHBUTTON "Del",IDC_DEL14,280,40,20,20 - PUSHBUTTON "Add",IDC_ASS13,255,65,20,20 - PUSHBUTTON "Del",IDC_DEL13,280,65,20,20 - PUSHBUTTON "Add",IDC_ASS12,255,90,20,20 - PUSHBUTTON "Del",IDC_DEL12,280,90,20,20 - PUSHBUTTON "Add",IDC_ASS11,255,115,20,20 - PUSHBUTTON "Del",IDC_DEL11,280,115,20,20 - GROUPBOX "Controller#4",IDC_STATIC,305,5,99,135 - LTEXT "Red",IDC_BZ_CTL4_LBL1,310,15,38,8 - LTEXT "Blue",IDC_BZ_CTL4_LBL2,310,40,38,8 - LTEXT "Orange",IDC_BZ_CTL4_LBL3,310,65,38,8 - LTEXT "Green",IDC_BZ_CTL4_LBL4,310,90,38,8 - LTEXT "Yellow",IDC_BZ_CTL4_LBL5,310,115,38,8 - LTEXT "1/1/1/1",IDC_LABEL15,310,27,38,8 - LTEXT "1/1/1/1",IDC_LABEL19,310,52,38,8 - LTEXT "1/1/1/1",IDC_LABEL18,310,77,38,8 - LTEXT "1/1/1/1",IDC_LABEL17,310,102,38,8 - LTEXT "1/1/1/1",IDC_LABEL16,310,127,38,8 - PUSHBUTTON "Add",IDC_ASS15,355,15,20,20 - PUSHBUTTON "Del",IDC_DEL15,380,15,20,20 - PUSHBUTTON "Add",IDC_ASS19,355,40,20,20 - PUSHBUTTON "Del",IDC_DEL19,380,40,20,20 - PUSHBUTTON "Add",IDC_ASS18,355,65,20,20 - PUSHBUTTON "Del",IDC_DEL18,380,65,20,20 - PUSHBUTTON "Add",IDC_ASS17,355,90,20,20 - PUSHBUTTON "Del",IDC_DEL17,380,90,20,20 - PUSHBUTTON "Add",IDC_ASS16,355,115,20,20 - PUSHBUTTON "Del",IDC_DEL16,380,115,20,20 - DEFPUSHBUTTON "OK",IDOK,302,142,50,14 - PUSHBUTTON "Cancel",IDCANCEL,354,142,50,14 -END - -IDD_DLG_KEYBOARDMANIA DIALOGEX 0, 0, 580, 160 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Keyboardmania controller" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - GROUPBOX "Buttons",IDC_STATIC,5,5,140,50 - PUSHBUTTON "Start",IDC_ASS22,90,15,50,15 - PUSHBUTTON "Select",IDC_ASS14,90,35,50,15 - LTEXT "1/1/1/1",IDC_LABEL22,10,17,50,8 - LTEXT "1/1/1/1",IDC_LABEL14,10,37,50,8 - GROUPBOX "Wheel",IDC_STATIC,150,5,140,50 - PUSHBUTTON "Up",IDC_ASS29,235,15,50,15 - PUSHBUTTON "Down",IDC_ASS30,235,35,50,15 - LTEXT "1/1/1/1",IDC_LABEL29,155,17,50,8 - LTEXT "1/1/1/1",IDC_LABEL30,155,37,50,8 - - GROUPBOX "Keys",IDC_STATIC,5,60,570,70 - PUSHBUTTON "C 1",IDC_ASS0,10,95,40,15 - PUSHBUTTON "C# 1",IDC_ASS1,30,80,40,15 - PUSHBUTTON "D 1",IDC_ASS2,50,95,40,15 - PUSHBUTTON "D# 1",IDC_ASS3,70,80,40,15 - PUSHBUTTON "E 1",IDC_ASS4,90,95,40,15 - PUSHBUTTON "F 1",IDC_ASS5,130,95,40,15 - PUSHBUTTON "F# 1",IDC_ASS6,150,80,40,15 - PUSHBUTTON "G 1",IDC_ASS8,170,95,40,15 - PUSHBUTTON "G# 1",IDC_ASS9,190,80,40,15 - PUSHBUTTON "A 1",IDC_ASS10,210,95,40,15 - PUSHBUTTON "A# 1",IDC_ASS11,230,80,40,15 - PUSHBUTTON "B 1",IDC_ASS12,250,95,40,15 - PUSHBUTTON "C 2",IDC_ASS13,290,95,40,15 - PUSHBUTTON "C# 2",IDC_ASS16,310,80,40,15 - PUSHBUTTON "D 2",IDC_ASS17,330,95,40,15 - PUSHBUTTON "D# 2",IDC_ASS18,350,80,40,15 - PUSHBUTTON "E 2",IDC_ASS19,370,95,40,15 - PUSHBUTTON "F 2",IDC_ASS20,410,95,40,15 - PUSHBUTTON "F# 2",IDC_ASS21,430,80,40,15 - PUSHBUTTON "G 2",IDC_ASS24,450,95,40,15 - PUSHBUTTON "G# 2",IDC_ASS25,470,80,40,15 - PUSHBUTTON "A 2",IDC_ASS26,490,95,40,15 - PUSHBUTTON "A# 2",IDC_ASS27,510,80,40,15 - PUSHBUTTON "B 2",IDC_ASS28,530,95,40,15 - LTEXT "1/1/1/1",IDC_LABEL0,10,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL1,30,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL2,50,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL3,70,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL4,90,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL5,130,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL6,150,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL8,170,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL9,190,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL10,210,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL11,230,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL12,250,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL13,290,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL16,310,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL17,330,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL18,350,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL19,370,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL20,410,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL21,430,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL24,450,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL25,470,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL26,490,110,38,8 - LTEXT "1/1/1/1",IDC_LABEL27,510,70,38,8 - LTEXT "1/1/1/1",IDC_LABEL28,530,110,38,8 - - PUSHBUTTON "Reset all",IDC_DELALL,5,140,50,15 - DEFPUSHBUTTON "OK",IDOK,470,140,50,15 - PUSHBUTTON "Cancel",IDCANCEL,525,140,50,15 -END - -IDD_DLG_GAMETRAK DIALOGEX 0, 0, 260, 115 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Gametrak" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Left X",IDC_ASS0,10,40,50,14 - PUSHBUTTON "Left Y",IDC_ASS1,70,40,50,14 - PUSHBUTTON "Left Z",IDC_ASS2,40,10,50,14 - PUSHBUTTON "Right X",IDC_ASS3,140,40,50,14 - PUSHBUTTON "Right Y",IDC_ASS4,200,40,50,14 - PUSHBUTTON "Right Z",IDC_ASS5,170,10,50,14 - PUSHBUTTON "Foot Mat",IDC_ASS6,105,70,50,14 - LTEXT "1/1/1/1",IDC_LABEL0,10,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL1,70,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL2,40,25,55,8 - LTEXT "1/1/1/1",IDC_LABEL3,140,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL4,200,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL5,170,25,55,8 - LTEXT "1/1/1/1",IDC_LABEL6,105,85,55,8 - DEFPUSHBUTTON "OK",IDOK,145,95,50,14 - PUSHBUTTON "Cancel",IDCANCEL,200,95,50,14 -END - -IDD_DLG_REALPLAY DIALOGEX 0, 0, 260, 151 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "RealPlay" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Up",IDC_ASS0,40,10,50,14 - PUSHBUTTON "Down",IDC_ASS1,40,70,50,14 - PUSHBUTTON "Left",IDC_ASS2,10,40,50,14 - PUSHBUTTON "Right",IDC_ASS3,70,40,50,14 - PUSHBUTTON "Red",IDC_ASS4,170,10,50,14 - PUSHBUTTON "Green",IDC_ASS5,170,70,50,14 - PUSHBUTTON "Yellow",IDC_ASS6,140,40,50,14 - PUSHBUTTON "Blue",IDC_ASS7,200,40,50,14 - PUSHBUTTON "Accel X",IDC_ASS8,45,100,50,14 - PUSHBUTTON "Accel Y",IDC_ASS9,105,100,50,14 - PUSHBUTTON "Accel Z",IDC_ASS10,165,100,50,14 - LTEXT "1/1/1/1",IDC_LABEL0,40,25,55,8 - LTEXT "1/1/1/1",IDC_LABEL1,40,85,55,8 - LTEXT "1/1/1/1",IDC_LABEL2,10,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL3,70,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL4,170,25,55,8 - LTEXT "1/1/1/1",IDC_LABEL5,170,85,55,8 - LTEXT "1/1/1/1",IDC_LABEL6,140,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL7,200,55,55,8 - LTEXT "1/1/1/1",IDC_LABEL8,45,115,55,8 - LTEXT "1/1/1/1",IDC_LABEL9,105,115,55,8 - LTEXT "1/1/1/1",IDC_LABEL10,165,115,55,8 - DEFPUSHBUTTON "OK",IDOK,145,130,50,14 - PUSHBUTTON "Cancel",IDCANCEL,200,130,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_DIALOG1, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 663 - TOPMARGIN, 7 - BOTTOMMARGIN, 302 - END - - IDD_DLG_BUZZ, DIALOG - BEGIN - END - - IDD_DLG_KEYBOARDMANIA, DIALOG - BEGIN - END - - IDD_DLG_GAMETRAK, DIALOG - BEGIN - END - - IDD_DLG_REALPLAY, DIALOG - BEGIN - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_DIALOG1 AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DLG_BUZZ AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DLG_KEYBOARDMANIA AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DLG_GAMETRAK AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_DLG_REALPLAY AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/pcsx2/USB/usb-pad/evdev/evdev-ff.cpp b/pcsx2/USB/usb-pad/evdev/evdev-ff.cpp deleted file mode 100644 index 5a055189ef..0000000000 --- a/pcsx2/USB/usb-pad/evdev/evdev-ff.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "evdev-ff.h" -#include "USB/usb-pad/lg/lg_ff.h" -#include -#include -#include - -namespace usb_pad -{ - namespace evdev - { - -#define BITS_TO_UCHAR(x) \ - (((x) + 8 * sizeof(unsigned char) - 1) / (8 * sizeof(unsigned char))) -#define testBit(bit, array) ((((uint8_t*)(array))[(bit) / 8] >> ((bit) % 8)) & 1) - - EvdevFF::EvdevFF(int fd, bool gain_enabled, int gain, bool ac_managed, int ac_strength) - : mHandle(fd) - , mUseRumble(false) - , mLastValue(0) - , m_gain_enabled(gain_enabled) - , m_gain(gain) - //, m_ac_managed(ac_enabled) - , m_ac_managed(true) - , m_ac_strength(ac_strength) - { - unsigned char features[BITS_TO_UCHAR(FF_MAX)]; - if (ioctl(mHandle, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) - { - } - - int effects = 0; - if (ioctl(mHandle, EVIOCGEFFECTS, &effects) < 0) - { - } - - if (!testBit(FF_CONSTANT, features)) - { - if (testBit(FF_RUMBLE, features)) - mUseRumble = true; - } - - if (!testBit(FF_SPRING, features)) - { - } - - if (!testBit(FF_DAMPER, features)) - { - } - - if (!testBit(FF_GAIN, features)) - { - } - - if (!testBit(FF_AUTOCENTER, features)) - { - } - - memset(&mEffect, 0, sizeof(mEffect)); - - // TODO check features and do FF_RUMBLE instead if gamepad? - // XXX linux status (hid-lg4ff.c) - only constant and autocenter are implemented - mEffect.u.constant.level = 0; /* Strength : 0x2000 == 25 % */ - // Logitech wheels' force vs turn direction: 255 - left, 127/128 - neutral, 0 - right - // left direction - mEffect.direction = 0x4000; - mEffect.trigger.button = 0; - mEffect.trigger.interval = 0; - mEffect.replay.length = 0x7FFFUL; /* mseconds */ - mEffect.replay.delay = 0; - - if (m_gain_enabled) - SetGain(m_gain); - - m_ac_strength = std::min(100, std::max(0, m_ac_strength)); - if (ac_managed) - SetAutoCenter(0); // default to off - else - SetAutoCenter(m_ac_strength); - - m_ac_managed = ac_managed; - } - - EvdevFF::~EvdevFF() - { - for (int i = 0; i < (int)countof(mEffIds); i++) - { - if (mEffIds[i] != -1 && ioctl(mHandle, EVIOCRMFF, mEffIds[i]) == -1) - { - } - } - } - - void EvdevFF::DisableForce(EffectID force) - { - struct input_event play; - play.type = EV_FF; - play.code = mEffIds[force]; - play.value = 0; - if (write(mHandle, (const void*)&play, sizeof(play)) == -1) - { - } - } - - void EvdevFF::SetConstantForce(/*const parsed_ff_data& ff*/ int level) - { - struct input_event play; - play.type = EV_FF; - play.value = 1; - mEffect.u = {}; - - if (!mUseRumble) - { - mEffect.type = FF_CONSTANT; - mEffect.id = mEffIds[EFF_CONSTANT]; - mEffect.u.constant.level = /*ff.u.constant.*/ level; - // mEffect.u.constant.envelope.attack_length = 0;//0x100; - // mEffect.u.constant.envelope.attack_level = 0; - // mEffect.u.constant.envelope.fade_length = 0;//0x100; - // mEffect.u.constant.envelope.fade_level = 0; - - if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) - { - return; - } - play.code = mEffect.id; - mEffIds[EFF_CONSTANT] = mEffect.id; - } - else - { - - mEffect.type = FF_RUMBLE; - mEffect.id = mEffIds[EFF_RUMBLE]; - - mEffect.replay.length = 500; - mEffect.replay.delay = 0; - mEffect.u.rumble.weak_magnitude = 0; - mEffect.u.rumble.strong_magnitude = 0; - - int mag = std::abs(/*ff.u.constant.*/ level); - int diff = std::abs(mag - mLastValue); - - // TODO random limits to cull down on too much rumble - if (diff > 8292 && diff < 32767) - mEffect.u.rumble.weak_magnitude = mag; - if (diff / 8192 > 0) - mEffect.u.rumble.strong_magnitude = mag; - - mLastValue = mag; - - if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) - { - return; - } - play.code = mEffect.id; - mEffIds[EFF_RUMBLE] = mEffect.id; - } - - if (write(mHandle, (const void*)&play, sizeof(play)) == -1) - { - } - } - - void EvdevFF::SetSpringForce(const parsed_ff_data& ff) - { - struct input_event play; - play.type = EV_FF; - play.value = 1; - - mEffect.type = FF_SPRING; - mEffect.id = mEffIds[EFF_SPRING]; - mEffect.u = {}; - mEffect.u.condition[0].left_saturation = ff.u.condition.left_saturation; - mEffect.u.condition[0].right_saturation = ff.u.condition.right_saturation; - mEffect.u.condition[0].left_coeff = ff.u.condition.left_coeff; - mEffect.u.condition[0].right_coeff = ff.u.condition.right_coeff; - mEffect.u.condition[0].center = ff.u.condition.center; - mEffect.u.condition[0].deadband = ff.u.condition.deadband; - - if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) - { - return; - } - - play.code = mEffect.id; - mEffIds[EFF_SPRING] = mEffect.id; - - if (write(mHandle, (const void*)&play, sizeof(play)) == -1) - { - } - } - - void EvdevFF::SetDamperForce(const parsed_ff_data& ff) - { - struct input_event play; - play.type = EV_FF; - play.value = 1; - - mEffect.u = {}; - mEffect.type = FF_DAMPER; - mEffect.id = mEffIds[EFF_DAMPER]; - mEffect.u.condition[0].left_saturation = ff.u.condition.left_saturation; - mEffect.u.condition[0].right_saturation = ff.u.condition.right_saturation; - mEffect.u.condition[0].left_coeff = ff.u.condition.left_coeff; - mEffect.u.condition[0].right_coeff = ff.u.condition.right_coeff; - mEffect.u.condition[0].center = ff.u.condition.center; - mEffect.u.condition[0].deadband = ff.u.condition.deadband; - - - if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) - { - return; - } - - play.code = mEffect.id; - mEffIds[EFF_DAMPER] = mEffect.id; - - if (write(mHandle, (const void*)&play, sizeof(play)) == -1) - { - } - } - - void EvdevFF::SetFrictionForce(const parsed_ff_data& ff) - { - struct input_event play; - play.type = EV_FF; - play.value = 1; - - mEffect.u = {}; - mEffect.type = FF_FRICTION; - mEffect.id = mEffIds[EFF_FRICTION]; - mEffect.u.condition[0].left_saturation = ff.u.condition.left_saturation; - mEffect.u.condition[0].right_saturation = ff.u.condition.right_saturation; - mEffect.u.condition[0].left_coeff = ff.u.condition.left_coeff; - mEffect.u.condition[0].right_coeff = ff.u.condition.right_coeff; - mEffect.u.condition[0].center = ff.u.condition.center; - mEffect.u.condition[0].deadband = ff.u.condition.deadband; - - if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) - { - return; - } - - play.code = mEffect.id; - mEffIds[EFF_FRICTION] = mEffect.id; - - if (write(mHandle, (const void*)&play, sizeof(play)) == -1) - { - } - } - - void EvdevFF::SetAutoCenter(int value) - { - if (!m_ac_managed) - return; - struct input_event ie; - value = value * m_ac_strength / 100; - - ie.type = EV_FF; - ie.code = FF_AUTOCENTER; - ie.value = value * 0xFFFFUL / 100; - - if (write(mHandle, &ie, sizeof(ie)) == -1) - { - } - } - - void EvdevFF::SetGain(int gain /* between 0 and 100 */) - { - struct input_event ie; - - ie.type = EV_FF; - ie.code = FF_GAIN; - ie.value = 0xFFFFUL * gain / 100; - - if (write(mHandle, &ie, sizeof(ie)) == -1) - { - } - } - - } // namespace evdev -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/evdev/evdev-ff.h b/pcsx2/USB/usb-pad/evdev/evdev-ff.h deleted file mode 100644 index 082cf988d9..0000000000 --- a/pcsx2/USB/usb-pad/evdev/evdev-ff.h +++ /dev/null @@ -1,56 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef EVDEV_FF_H -#define EVDEV_FF_H - -#include -#include "USB/usb-pad/usb-pad.h" - -namespace usb_pad -{ - namespace evdev - { - - class EvdevFF : public FFDevice - { - public: - EvdevFF(int fd, bool gain_enabled, int gain, bool ac_managed, int ac_strength); - ~EvdevFF(); - - void SetConstantForce(int level); - void SetSpringForce(const parsed_ff_data& ff); - void SetDamperForce(const parsed_ff_data& ff); - void SetFrictionForce(const parsed_ff_data& ff); - void SetAutoCenter(int value); - void SetGain(int gain); - void DisableForce(EffectID force); - - private: - int mHandle; - ff_effect mEffect; - int mEffIds[5] = {-1, -1, -1, -1, -1}; //save ids just in case - - bool mUseRumble; - int mLastValue; - bool m_gain_enabled; - int m_gain; - bool m_ac_managed; - int m_ac_strength; - }; - - } // namespace evdev -} // namespace usb_pad -#endif diff --git a/pcsx2/USB/usb-pad/evdev/evdev-gtk.cpp b/pcsx2/USB/usb-pad/evdev/evdev-gtk.cpp deleted file mode 100644 index e4d6718966..0000000000 --- a/pcsx2/USB/usb-pad/evdev/evdev-gtk.cpp +++ /dev/null @@ -1,754 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "evdev.h" - -#include -#include -#include -#include -#include "USB/gtk.h" - -namespace usb_pad -{ - namespace evdev - { - - using sys_clock = std::chrono::system_clock; - using ms = std::chrono::milliseconds; - -#define EVDEV_DIR "/dev/input/by-id/" - - const std::array key_to_str = { - "RESERVED", /* linux:0 (KEY_RESERVED) */ - "ESC", /* linux:1 (KEY_ESC) */ - "1", /* linux:2 (KEY_1) */ - "2", /* linux:3 (KEY_2) */ - "3", /* linux:4 (KEY_3) */ - "4", /* linux:5 (KEY_4) */ - "5", /* linux:6 (KEY_5) */ - "6", /* linux:7 (KEY_6) */ - "7", /* linux:8 (KEY_7) */ - "8", /* linux:9 (KEY_8) */ - "9", /* linux:10 (KEY_9) */ - "0", /* linux:11 (KEY_0) */ - "MINUS", /* linux:12 (KEY_MINUS) */ - "EQUAL", /* linux:13 (KEY_EQUAL) */ - "BACKSPACE", /* linux:14 (KEY_BACKSPACE) */ - "TAB", /* linux:15 (KEY_TAB) */ - "Q", /* linux:16 (KEY_Q) */ - "W", /* linux:17 (KEY_W) */ - "E", /* linux:18 (KEY_E) */ - "R", /* linux:19 (KEY_R) */ - "T", /* linux:20 (KEY_T) */ - "Y", /* linux:21 (KEY_Y) */ - "U", /* linux:22 (KEY_U) */ - "I", /* linux:23 (KEY_I) */ - "O", /* linux:24 (KEY_O) */ - "P", /* linux:25 (KEY_P) */ - "{", /* linux:26 (KEY_LEFTBRACE) */ - "}", /* linux:27 (KEY_RIGHTBRACE) */ - "ENTER", /* linux:28 (KEY_ENTER) */ - "L-CTRL", /* linux:29 (KEY_LEFTCTRL) */ - "A", /* linux:30 (KEY_A) */ - "S", /* linux:31 (KEY_S) */ - "D", /* linux:32 (KEY_D) */ - "F", /* linux:33 (KEY_F) */ - "G", /* linux:34 (KEY_G) */ - "H", /* linux:35 (KEY_H) */ - "J", /* linux:36 (KEY_J) */ - "K", /* linux:37 (KEY_K) */ - "L", /* linux:38 (KEY_L) */ - ";", /* linux:39 (KEY_SEMICOLON) */ - "'", /* linux:40 (KEY_APOSTROPHE) */ - "~", /* linux:41 (KEY_GRAVE) */ - "L-SHIFT", /* linux:42 (KEY_LEFTSHIFT) */ - "\\", /* linux:43 (KEY_BACKSLASH) */ - "Z", /* linux:44 (KEY_Z) */ - "X", /* linux:45 (KEY_X) */ - "C", /* linux:46 (KEY_C) */ - "V", /* linux:47 (KEY_V) */ - "B", /* linux:48 (KEY_B) */ - "N", /* linux:49 (KEY_N) */ - "M", /* linux:50 (KEY_M) */ - ",", /* linux:51 (KEY_COMMA) */ - ".", /* linux:52 (KEY_DOT) */ - "/", /* linux:53 (KEY_SLASH) */ - "R-SHIFT", /* linux:54 (KEY_RIGHTSHIFT) */ - "KPASTERISK", /* linux:55 (KEY_KPASTERISK) */ - "LEFTALT", /* linux:56 (KEY_LEFTALT) */ - "SPACE", /* linux:57 (KEY_SPACE) */ - "CAPSLOCK", /* linux:58 (KEY_CAPSLOCK) */ - "F1", /* linux:59 (KEY_F1) */ - "F2", /* linux:60 (KEY_F2) */ - "F3", /* linux:61 (KEY_F3) */ - "F4", /* linux:62 (KEY_F4) */ - "F5", /* linux:63 (KEY_F5) */ - "F6", /* linux:64 (KEY_F6) */ - "F7", /* linux:65 (KEY_F7) */ - "F8", /* linux:66 (KEY_F8) */ - "F9", /* linux:67 (KEY_F9) */ - "F10", /* linux:68 (KEY_F10) */ - "NUMLOCK", /* linux:69 (KEY_NUMLOCK) */ - "SCROLLLOCK", /* linux:70 (KEY_SCROLLLOCK) */ - "KP7", /* linux:71 (KEY_KP7) */ - "KP8", /* linux:72 (KEY_KP8) */ - "KP9", /* linux:73 (KEY_KP9) */ - "KPMINUS", /* linux:74 (KEY_KPMINUS) */ - "KP4", /* linux:75 (KEY_KP4) */ - "KP5", /* linux:76 (KEY_KP5) */ - "KP6", /* linux:77 (KEY_KP6) */ - "KPPLUS", /* linux:78 (KEY_KPPLUS) */ - "KP1", /* linux:79 (KEY_KP1) */ - "KP2", /* linux:80 (KEY_KP2) */ - "KP3", /* linux:81 (KEY_KP3) */ - "KP0", /* linux:82 (KEY_KP0) */ - "KPDOT", /* linux:83 (KEY_KPDOT) */ - "84", /* linux:84 (unnamed) */ - "ZENKAKUHANKAKU", /* linux:85 (KEY_ZENKAKUHANKAKU) */ - "102ND", /* linux:86 (KEY_102ND) */ - "F11", /* linux:87 (KEY_F11) */ - "F12", /* linux:88 (KEY_F12) */ - "RO", /* linux:89 (KEY_RO) */ - "KATAKANA", /* linux:90 (KEY_KATAKANA) */ - "HIRAGANA", /* linux:91 (KEY_HIRAGANA) */ - "HENKAN", /* linux:92 (KEY_HENKAN) */ - "KATAKANAHIRAGANA", /* linux:93 (KEY_KATAKANAHIRAGANA) */ - "MUHENKAN", /* linux:94 (KEY_MUHENKAN) */ - "KPJPCOMMA", /* linux:95 (KEY_KPJPCOMMA) */ - "KPENTER", /* linux:96 (KEY_KPENTER) */ - "RIGHTCTRL", /* linux:97 (KEY_RIGHTCTRL) */ - "KPSLASH", /* linux:98 (KEY_KPSLASH) */ - "SYSRQ", /* linux:99 (KEY_SYSRQ) */ - "RIGHTALT", /* linux:100 (KEY_RIGHTALT) */ - "LINEFEED", /* linux:101 (KEY_LINEFEED) */ - "HOME", /* linux:102 (KEY_HOME) */ - "UP", /* linux:103 (KEY_UP) */ - "PAGEUP", /* linux:104 (KEY_PAGEUP) */ - "LEFT", /* linux:105 (KEY_LEFT) */ - "RIGHT", /* linux:106 (KEY_RIGHT) */ - "END", /* linux:107 (KEY_END) */ - "DOWN", /* linux:108 (KEY_DOWN) */ - "PAGEDOWN", /* linux:109 (KEY_PAGEDOWN) */ - "INSERT", /* linux:110 (KEY_INSERT) */ - "DELETE", /* linux:111 (KEY_DELETE) */ - "MACRO", /* linux:112 (KEY_MACRO) */ - "MUTE", /* linux:113 (KEY_MUTE) */ - "VOLUMEDOWN", /* linux:114 (KEY_VOLUMEDOWN) */ - "VOLUMEUP", /* linux:115 (KEY_VOLUMEUP) */ - "POWER", /* linux:116 (KEY_POWER) */ - "KPEQUAL", /* linux:117 (KEY_KPEQUAL) */ - "KPPLUSMINUS", /* linux:118 (KEY_KPPLUSMINUS) */ - "PAUSE", /* linux:119 (KEY_PAUSE) */ - "SCALE", /* linux:120 (KEY_SCALE) */ - "KPCOMMA", /* linux:121 (KEY_KPCOMMA) */ - "HANGEUL", /* linux:122 (KEY_HANGEUL) */ - "HANJA", /* linux:123 (KEY_HANJA) */ - "YEN", /* linux:124 (KEY_YEN) */ - "LEFTMETA", /* linux:125 (KEY_LEFTMETA) */ - "RIGHTMETA", /* linux:126 (KEY_RIGHTMETA) */ - "COMPOSE", /* linux:127 (KEY_COMPOSE) */ - "STOP", /* linux:128 (KEY_STOP) */ - "AGAIN", /* linux:129 (KEY_AGAIN) */ - "PROPS", /* linux:130 (KEY_PROPS) */ - "UNDO", /* linux:131 (KEY_UNDO) */ - "FRONT", /* linux:132 (KEY_FRONT) */ - "COPY", /* linux:133 (KEY_COPY) */ - "OPEN", /* linux:134 (KEY_OPEN) */ - "PASTE", /* linux:135 (KEY_PASTE) */ - "FIND", /* linux:136 (KEY_FIND) */ - "CUT", /* linux:137 (KEY_CUT) */ - "HELP", /* linux:138 (KEY_HELP) */ - "MENU", /* linux:139 (KEY_MENU) */ - "CALC", /* linux:140 (KEY_CALC) */ - "SETUP", /* linux:141 (KEY_SETUP) */ - "SLEEP", /* linux:142 (KEY_SLEEP) */ - "WAKEUP", /* linux:143 (KEY_WAKEUP) */ - "FILE", /* linux:144 (KEY_FILE) */ - "SENDFILE", /* linux:145 (KEY_SENDFILE) */ - "DELETEFILE", /* linux:146 (KEY_DELETEFILE) */ - "XFER", /* linux:147 (KEY_XFER) */ - "PROG1", /* linux:148 (KEY_PROG1) */ - "PROG2", /* linux:149 (KEY_PROG2) */ - "WWW", /* linux:150 (KEY_WWW) */ - "MSDOS", /* linux:151 (KEY_MSDOS) */ - "SCREENLOCK", /* linux:152 (KEY_SCREENLOCK) */ - "DIRECTION", /* linux:153 (KEY_DIRECTION) */ - "CYCLEWINDOWS", /* linux:154 (KEY_CYCLEWINDOWS) */ - "MAIL", /* linux:155 (KEY_MAIL) */ - "BOOKMARKS", /* linux:156 (KEY_BOOKMARKS) */ - "COMPUTER", /* linux:157 (KEY_COMPUTER) */ - "BACK", /* linux:158 (KEY_BACK) */ - "FORWARD", /* linux:159 (KEY_FORWARD) */ - "CLOSECD", /* linux:160 (KEY_CLOSECD) */ - "EJECTCD", /* linux:161 (KEY_EJECTCD) */ - "EJECTCLOSECD", /* linux:162 (KEY_EJECTCLOSECD) */ - "NEXTSONG", /* linux:163 (KEY_NEXTSONG) */ - "PLAYPAUSE", /* linux:164 (KEY_PLAYPAUSE) */ - "PREVIOUSSONG", /* linux:165 (KEY_PREVIOUSSONG) */ - "STOPCD", /* linux:166 (KEY_STOPCD) */ - "RECORD", /* linux:167 (KEY_RECORD) */ - "REWIND", /* linux:168 (KEY_REWIND) */ - "PHONE", /* linux:169 (KEY_PHONE) */ - "ISO", /* linux:170 (KEY_ISO) */ - "CONFIG", /* linux:171 (KEY_CONFIG) */ - "HOMEPAGE", /* linux:172 (KEY_HOMEPAGE) */ - "REFRESH", /* linux:173 (KEY_REFRESH) */ - "EXIT", /* linux:174 (KEY_EXIT) */ - "MOVE", /* linux:175 (KEY_MOVE) */ - "EDIT", /* linux:176 (KEY_EDIT) */ - "SCROLLUP", /* linux:177 (KEY_SCROLLUP) */ - "SCROLLDOWN", /* linux:178 (KEY_SCROLLDOWN) */ - "KPLEFTPAREN", /* linux:179 (KEY_KPLEFTPAREN) */ - "KPRIGHTPAREN", /* linux:180 (KEY_KPRIGHTPAREN) */ - "NEW", /* linux:181 (KEY_NEW) */ - "REDO", /* linux:182 (KEY_REDO) */ - "F13", /* linux:183 (KEY_F13) */ - "F14", /* linux:184 (KEY_F14) */ - "F15", /* linux:185 (KEY_F15) */ - "F16", /* linux:186 (KEY_F16) */ - "F17", /* linux:187 (KEY_F17) */ - "F18", /* linux:188 (KEY_F18) */ - "F19", /* linux:189 (KEY_F19) */ - "F20", /* linux:190 (KEY_F20) */ - "F21", /* linux:191 (KEY_F21) */ - "F22", /* linux:192 (KEY_F22) */ - "F23", /* linux:193 (KEY_F23) */ - "F24", /* linux:194 (KEY_F24) */ - "195", /* linux:195 (unnamed) */ - "196", /* linux:196 (unnamed) */ - "197", /* linux:197 (unnamed) */ - "198", /* linux:198 (unnamed) */ - "199", /* linux:199 (unnamed) */ - "PLAYCD", /* linux:200 (KEY_PLAYCD) */ - "PAUSECD", /* linux:201 (KEY_PAUSECD) */ - "PROG3", /* linux:202 (KEY_PROG3) */ - "PROG4", /* linux:203 (KEY_PROG4) */ - "DASHBOARD", /* linux:204 (KEY_DASHBOARD) */ - "SUSPEND", /* linux:205 (KEY_SUSPEND) */ - "CLOSE", /* linux:206 (KEY_CLOSE) */ - "PLAY", /* linux:207 (KEY_PLAY) */ - "FASTFORWARD", /* linux:208 (KEY_FASTFORWARD) */ - "BASSBOOST", /* linux:209 (KEY_BASSBOOST) */ - "PRINT", /* linux:210 (KEY_PRINT) */ - "HP", /* linux:211 (KEY_HP) */ - "CAMERA", /* linux:212 (KEY_CAMERA) */ - "SOUND", /* linux:213 (KEY_SOUND) */ - "QUESTION", /* linux:214 (KEY_QUESTION) */ - "EMAIL", /* linux:215 (KEY_EMAIL) */ - "CHAT", /* linux:216 (KEY_CHAT) */ - "SEARCH", /* linux:217 (KEY_SEARCH) */ - "CONNECT", /* linux:218 (KEY_CONNECT) */ - "FINANCE", /* linux:219 (KEY_FINANCE) */ - "SPORT", /* linux:220 (KEY_SPORT) */ - "SHOP", /* linux:221 (KEY_SHOP) */ - "ALTERASE", /* linux:222 (KEY_ALTERASE) */ - "CANCEL", /* linux:223 (KEY_CANCEL) */ - "BRIGHTNESSDOWN", /* linux:224 (KEY_BRIGHTNESSDOWN) */ - "BRIGHTNESSUP", /* linux:225 (KEY_BRIGHTNESSUP) */ - "MEDIA", /* linux:226 (KEY_MEDIA) */ - "SWITCHVIDEOMODE", /* linux:227 (KEY_SWITCHVIDEOMODE) */ - "KBDILLUMTOGGLE", /* linux:228 (KEY_KBDILLUMTOGGLE) */ - "KBDILLUMDOWN", /* linux:229 (KEY_KBDILLUMDOWN) */ - "KBDILLUMUP", /* linux:230 (KEY_KBDILLUMUP) */ - "SEND", /* linux:231 (KEY_SEND) */ - "REPLY", /* linux:232 (KEY_REPLY) */ - "FORWARDMAIL", /* linux:233 (KEY_FORWARDMAIL) */ - "SAVE", /* linux:234 (KEY_SAVE) */ - "DOCUMENTS", /* linux:235 (KEY_DOCUMENTS) */ - "BATTERY", /* linux:236 (KEY_BATTERY) */ - "BLUETOOTH", /* linux:237 (KEY_BLUETOOTH) */ - "WLAN", /* linux:238 (KEY_WLAN) */ - "UWB", /* linux:239 (KEY_UWB) */ - "UNKNOWN", /* linux:240 (KEY_UNKNOWN) */ - "VIDEO_NEXT", /* linux:241 (KEY_VIDEO_NEXT) */ - "VIDEO_PREV", /* linux:242 (KEY_VIDEO_PREV) */ - "BRIGHTNESS_CYCLE", /* linux:243 (KEY_BRIGHTNESS_CYCLE) */ - "BRIGHTNESS_ZERO", /* linux:244 (KEY_BRIGHTNESS_ZERO) */ - "DISPLAY_OFF", /* linux:245 (KEY_DISPLAY_OFF) */ - "WIMAX", /* linux:246 (KEY_WIMAX) */ - "RFKILL", /* linux:247 (KEY_RFKILL) */ - "MICMUTE", /* linux:248 (KEY_MICMUTE) */ - "249", /* linux:249 (unnamed) */ - "250", /* linux:250 (unnamed) */ - "251", /* linux:251 (unnamed) */ - "252", /* linux:252 (unnamed) */ - "253", /* linux:253 (unnamed) */ - "254", /* linux:254 (unnamed) */ - "255", /* linux:255 (unnamed) */ - "BTN_0", /* linux:256 (BTN_0) */ - "BTN_1", /* linux:257 (BTN_1) */ - "BTN_2", /* linux:258 (BTN_2) */ - "BTN_3", /* linux:259 (BTN_3) */ - "BTN_4", /* linux:260 (BTN_4) */ - "BTN_5", /* linux:261 (BTN_5) */ - "BTN_6", /* linux:262 (BTN_6) */ - "BTN_7", /* linux:263 (BTN_7) */ - "BTN_8", /* linux:264 (BTN_8) */ - "BTN_9", /* linux:265 (BTN_9) */ - "266", /* linux:266 (unnamed) */ - "267", /* linux:267 (unnamed) */ - "268", /* linux:268 (unnamed) */ - "269", /* linux:269 (unnamed) */ - "270", /* linux:270 (unnamed) */ - "271", /* linux:271 (unnamed) */ - "BTN_LEFT", /* linux:272 (BTN_LEFT) */ - "BTN_RIGHT", /* linux:273 (BTN_RIGHT) */ - "BTN_MIDDLE", /* linux:274 (BTN_MIDDLE) */ - "BTN_SIDE", /* linux:275 (BTN_SIDE) */ - "BTN_EXTRA", /* linux:276 (BTN_EXTRA) */ - "BTN_FORWARD", /* linux:277 (BTN_FORWARD) */ - "BTN_BACK", /* linux:278 (BTN_BACK) */ - "BTN_TASK", /* linux:279 (BTN_TASK) */ - "280", /* linux:280 (unnamed) */ - "281", /* linux:281 (unnamed) */ - "282", /* linux:282 (unnamed) */ - "283", /* linux:283 (unnamed) */ - "284", /* linux:284 (unnamed) */ - "285", /* linux:285 (unnamed) */ - "286", /* linux:286 (unnamed) */ - "287", /* linux:287 (unnamed) */ - "TRIGGER", /* linux:288 (BTN_TRIGGER) */ - "THUMB", /* linux:289 (BTN_THUMB) */ - "THUMB2", /* linux:290 (BTN_THUMB2) */ - "TOP", /* linux:291 (BTN_TOP) */ - "TOP2", /* linux:292 (BTN_TOP2) */ - "PINKIE", /* linux:293 (BTN_PINKIE) */ - "BASE", /* linux:294 (BTN_BASE) */ - "BASE2", /* linux:295 (BTN_BASE2) */ - "BASE3", /* linux:296 (BTN_BASE3) */ - "BASE4", /* linux:297 (BTN_BASE4) */ - "BASE5", /* linux:298 (BTN_BASE5) */ - "BASE6", /* linux:299 (BTN_BASE6) */ - "300", /* linux:300 (unnamed) */ - "301", /* linux:301 (unnamed) */ - "302", /* linux:302 (unnamed) */ - "DEAD", /* linux:303 (BTN_DEAD) */ - "BTN_A", /* linux:304 (BTN_A) */ - "BTN_B", /* linux:305 (BTN_B) */ - "BTN_C", /* linux:306 (BTN_C) */ - "BTN_X", /* linux:307 (BTN_X) */ - "BTN_Y", /* linux:308 (BTN_Y) */ - "BTN_Z", /* linux:309 (BTN_Z) */ - "TL", /* linux:310 (BTN_TL) */ - "TR", /* linux:311 (BTN_TR) */ - "TL2", /* linux:312 (BTN_TL2) */ - "TR2", /* linux:313 (BTN_TR2) */ - "SELECT", /* linux:314 (BTN_SELECT) */ - "START", /* linux:315 (BTN_START) */ - "MODE", /* linux:316 (BTN_MODE) */ - "THUMBL", /* linux:317 (BTN_THUMBL) */ - "THUMBR", /* linux:318 (BTN_THUMBR) */ - "319", /* linux:319 (unnamed) */ - "TOOL_PEN", /* linux:320 (BTN_TOOL_PEN) */ - "TOOL_RUBBER", /* linux:321 (BTN_TOOL_RUBBER) */ - "TOOL_BRUSH", /* linux:322 (BTN_TOOL_BRUSH) */ - "TOOL_PENCIL", /* linux:323 (BTN_TOOL_PENCIL) */ - "TOOL_AIRBRUSH", /* linux:324 (BTN_TOOL_AIRBRUSH) */ - "TOOL_FINGER", /* linux:325 (BTN_TOOL_FINGER) */ - "TOOL_MOUSE", /* linux:326 (BTN_TOOL_MOUSE) */ - "TOOL_LENS", /* linux:327 (BTN_TOOL_LENS) */ - "328", /* linux:328 (unnamed) */ - "329", /* linux:329 (unnamed) */ - "TOUCH", /* linux:330 (BTN_TOUCH) */ - "STYLUS", /* linux:331 (BTN_STYLUS) */ - "STYLUS2", /* linux:332 (BTN_STYLUS2) */ - "TOOL_DOUBLETAP", /* linux:333 (BTN_TOOL_DOUBLETAP) */ - "TOOL_TRIPLETAP", /* linux:334 (BTN_TOOL_TRIPLETAP) */ - "TOOL_QUADTAP", /* linux:335 (BTN_TOOL_QUADTAP) */ - "GEAR_DOWN", /* linux:336 (BTN_GEAR_DOWN) */ - "GEAR_UP", /* linux:337 (BTN_GEAR_UP) */ - "338", /* linux:338 (unnamed) */ - "339", /* linux:339 (unnamed) */ - "340", /* linux:340 (unnamed) */ - "341", /* linux:341 (unnamed) */ - "342", /* linux:342 (unnamed) */ - "343", /* linux:343 (unnamed) */ - "344", /* linux:344 (unnamed) */ - "345", /* linux:345 (unnamed) */ - "346", /* linux:346 (unnamed) */ - "347", /* linux:347 (unnamed) */ - "348", /* linux:348 (unnamed) */ - "349", /* linux:349 (unnamed) */ - "350", /* linux:350 (unnamed) */ - "351", /* linux:351 (unnamed) */ - "OK", /* linux:352 (KEY_OK) */ - "SELECT", /* linux:353 (KEY_SELECT) */ - "GOTO", /* linux:354 (KEY_GOTO) */ - "CLEAR", /* linux:355 (KEY_CLEAR) */ - "POWER2", /* linux:356 (KEY_POWER2) */ - "OPTION", /* linux:357 (KEY_OPTION) */ - "INFO", /* linux:358 (KEY_INFO) */ - "TIME", /* linux:359 (KEY_TIME) */ - "VENDOR", /* linux:360 (KEY_VENDOR) */ - "ARCHIVE", /* linux:361 (KEY_ARCHIVE) */ - "PROGRAM", /* linux:362 (KEY_PROGRAM) */ - "CHANNEL", /* linux:363 (KEY_CHANNEL) */ - "FAVORITES", /* linux:364 (KEY_FAVORITES) */ - "EPG", /* linux:365 (KEY_EPG) */ - "PVR", /* linux:366 (KEY_PVR) */ - "MHP", /* linux:367 (KEY_MHP) */ - "LANGUAGE", /* linux:368 (KEY_LANGUAGE) */ - "TITLE", /* linux:369 (KEY_TITLE) */ - "SUBTITLE", /* linux:370 (KEY_SUBTITLE) */ - "ANGLE", /* linux:371 (KEY_ANGLE) */ - "ZOOM", /* linux:372 (KEY_ZOOM) */ - "MODE", /* linux:373 (KEY_MODE) */ - "KEYBOARD", /* linux:374 (KEY_KEYBOARD) */ - "SCREEN", /* linux:375 (KEY_SCREEN) */ - "PC", /* linux:376 (KEY_PC) */ - "TV", /* linux:377 (KEY_TV) */ - "TV2", /* linux:378 (KEY_TV2) */ - "VCR", /* linux:379 (KEY_VCR) */ - "VCR2", /* linux:380 (KEY_VCR2) */ - "SAT", /* linux:381 (KEY_SAT) */ - "SAT2", /* linux:382 (KEY_SAT2) */ - "CD", /* linux:383 (KEY_CD) */ - "TAPE", /* linux:384 (KEY_TAPE) */ - "RADIO", /* linux:385 (KEY_RADIO) */ - "TUNER", /* linux:386 (KEY_TUNER) */ - "PLAYER", /* linux:387 (KEY_PLAYER) */ - "TEXT", /* linux:388 (KEY_TEXT) */ - "DVD", /* linux:389 (KEY_DVD) */ - "AUX", /* linux:390 (KEY_AUX) */ - "MP3", /* linux:391 (KEY_MP3) */ - "AUDIO", /* linux:392 (KEY_AUDIO) */ - "VIDEO", /* linux:393 (KEY_VIDEO) */ - "DIRECTORY", /* linux:394 (KEY_DIRECTORY) */ - "LIST", /* linux:395 (KEY_LIST) */ - "MEMO", /* linux:396 (KEY_MEMO) */ - "CALENDAR", /* linux:397 (KEY_CALENDAR) */ - "RED", /* linux:398 (KEY_RED) */ - "GREEN", /* linux:399 (KEY_GREEN) */ - "YELLOW", /* linux:400 (KEY_YELLOW) */ - "BLUE", /* linux:401 (KEY_BLUE) */ - "CHANNELUP", /* linux:402 (KEY_CHANNELUP) */ - "CHANNELDOWN", /* linux:403 (KEY_CHANNELDOWN) */ - "FIRST", /* linux:404 (KEY_FIRST) */ - "LAST", /* linux:405 (KEY_LAST) */ - "AB", /* linux:406 (KEY_AB) */ - "NEXT", /* linux:407 (KEY_NEXT) */ - "RESTART", /* linux:408 (KEY_RESTART) */ - "SLOW", /* linux:409 (KEY_SLOW) */ - "SHUFFLE", /* linux:410 (KEY_SHUFFLE) */ - "BREAK", /* linux:411 (KEY_BREAK) */ - "PREVIOUS", /* linux:412 (KEY_PREVIOUS) */ - "DIGITS", /* linux:413 (KEY_DIGITS) */ - "TEEN", /* linux:414 (KEY_TEEN) */ - "TWEN", /* linux:415 (KEY_TWEN) */ - "VIDEOPHONE", /* linux:416 (KEY_VIDEOPHONE) */ - "GAMES", /* linux:417 (KEY_GAMES) */ - "ZOOMIN", /* linux:418 (KEY_ZOOMIN) */ - "ZOOMOUT", /* linux:419 (KEY_ZOOMOUT) */ - "ZOOMRESET", /* linux:420 (KEY_ZOOMRESET) */ - "WORDPROCESSOR", /* linux:421 (KEY_WORDPROCESSOR) */ - "EDITOR", /* linux:422 (KEY_EDITOR) */ - "SPREADSHEET", /* linux:423 (KEY_SPREADSHEET) */ - "GRAPHICSEDITOR", /* linux:424 (KEY_GRAPHICSEDITOR) */ - "PRESENTATION", /* linux:425 (KEY_PRESENTATION) */ - "DATABASE", /* linux:426 (KEY_DATABASE) */ - "NEWS", /* linux:427 (KEY_NEWS) */ - "VOICEMAIL", /* linux:428 (KEY_VOICEMAIL) */ - "ADDRESSBOOK", /* linux:429 (KEY_ADDRESSBOOK) */ - "MESSENGER", /* linux:430 (KEY_MESSENGER) */ - "DISPLAYTOGGLE", /* linux:431 (KEY_DISPLAYTOGGLE) */ - "SPELLCHECK", /* linux:432 (KEY_SPELLCHECK) */ - "LOGOFF", /* linux:433 (KEY_LOGOFF) */ - "DOLLAR", /* linux:434 (KEY_DOLLAR) */ - "EURO", /* linux:435 (KEY_EURO) */ - "FRAMEBACK", /* linux:436 (KEY_FRAMEBACK) */ - "FRAMEFORWARD", /* linux:437 (KEY_FRAMEFORWARD) */ - "CONTEXT_MENU", /* linux:438 (KEY_CONTEXT_MENU) */ - "MEDIA_REPEAT", /* linux:439 (KEY_MEDIA_REPEAT) */ - "440", /* linux:440 (unnamed) */ - "441", /* linux:441 (unnamed) */ - "442", /* linux:442 (unnamed) */ - "443", /* linux:443 (unnamed) */ - "444", /* linux:444 (unnamed) */ - "445", /* linux:445 (unnamed) */ - "446", /* linux:446 (unnamed) */ - "447", /* linux:447 (unnamed) */ - "DEL_EOL", /* linux:448 (KEY_DEL_EOL) */ - "DEL_EOS", /* linux:449 (KEY_DEL_EOS) */ - "INS_LINE", /* linux:450 (KEY_INS_LINE) */ - "DEL_LINE", /* linux:451 (KEY_DEL_LINE) */ - "452", /* linux:452 (unnamed) */ - "453", /* linux:453 (unnamed) */ - "454", /* linux:454 (unnamed) */ - "455", /* linux:455 (unnamed) */ - "456", /* linux:456 (unnamed) */ - "457", /* linux:457 (unnamed) */ - "458", /* linux:458 (unnamed) */ - "459", /* linux:459 (unnamed) */ - "460", /* linux:460 (unnamed) */ - "461", /* linux:461 (unnamed) */ - "462", /* linux:462 (unnamed) */ - "463", /* linux:463 (unnamed) */ - "FN", /* linux:464 (KEY_FN) */ - "FN_ESC", /* linux:465 (KEY_FN_ESC) */ - "FN_F1", /* linux:466 (KEY_FN_F1) */ - "FN_F2", /* linux:467 (KEY_FN_F2) */ - "FN_F3", /* linux:468 (KEY_FN_F3) */ - "FN_F4", /* linux:469 (KEY_FN_F4) */ - "FN_F5", /* linux:470 (KEY_FN_F5) */ - "FN_F6", /* linux:471 (KEY_FN_F6) */ - "FN_F7", /* linux:472 (KEY_FN_F7) */ - "FN_F8", /* linux:473 (KEY_FN_F8) */ - "FN_F9", /* linux:474 (KEY_FN_F9) */ - "FN_F10", /* linux:475 (KEY_FN_F10) */ - "FN_F11", /* linux:476 (KEY_FN_F11) */ - "FN_F12", /* linux:477 (KEY_FN_F12) */ - "FN_1", /* linux:478 (KEY_FN_1) */ - "FN_2", /* linux:479 (KEY_FN_2) */ - "FN_D", /* linux:480 (KEY_FN_D) */ - "FN_E", /* linux:481 (KEY_FN_E) */ - "FN_F", /* linux:482 (KEY_FN_F) */ - "FN_S", /* linux:483 (KEY_FN_S) */ - "FN_B", /* linux:484 (KEY_FN_B) */ - "485", /* linux:485 (unnamed) */ - "486", /* linux:486 (unnamed) */ - "487", /* linux:487 (unnamed) */ - "488", /* linux:488 (unnamed) */ - "489", /* linux:489 (unnamed) */ - "490", /* linux:490 (unnamed) */ - "491", /* linux:491 (unnamed) */ - "492", /* linux:492 (unnamed) */ - "493", /* linux:493 (unnamed) */ - "494", /* linux:494 (unnamed) */ - "495", /* linux:495 (unnamed) */ - "496", /* linux:496 (unnamed) */ - "BRL_DOT1", /* linux:497 (KEY_BRL_DOT1) */ - "BRL_DOT2", /* linux:498 (KEY_BRL_DOT2) */ - "BRL_DOT3", /* linux:499 (KEY_BRL_DOT3) */ - "BRL_DOT4", /* linux:500 (KEY_BRL_DOT4) */ - "BRL_DOT5", /* linux:501 (KEY_BRL_DOT5) */ - "BRL_DOT6", /* linux:502 (KEY_BRL_DOT6) */ - "BRL_DOT7", /* linux:503 (KEY_BRL_DOT7) */ - "BRL_DOT8", /* linux:504 (KEY_BRL_DOT8) */ - "BRL_DOT9", /* linux:505 (KEY_BRL_DOT9) */ - "BRL_DOT10", /* linux:506 (KEY_BRL_DOT10) */ - "507", /* linux:507 (unnamed) */ - "508", /* linux:508 (unnamed) */ - "509", /* linux:509 (unnamed) */ - "510", /* linux:510 (unnamed) */ - "511", /* linux:511 (unnamed) */ - "NUMERIC_0", /* linux:512 (KEY_NUMERIC_0) */ - "NUMERIC_1", /* linux:513 (KEY_NUMERIC_1) */ - "NUMERIC_2", /* linux:514 (KEY_NUMERIC_2) */ - "NUMERIC_3", /* linux:515 (KEY_NUMERIC_3) */ - "NUMERIC_4", /* linux:516 (KEY_NUMERIC_4) */ - "NUMERIC_5", /* linux:517 (KEY_NUMERIC_5) */ - "NUMERIC_6", /* linux:518 (KEY_NUMERIC_6) */ - "NUMERIC_7", /* linux:519 (KEY_NUMERIC_7) */ - "NUMERIC_8", /* linux:520 (KEY_NUMERIC_8) */ - "NUMERIC_9", /* linux:521 (KEY_NUMERIC_9) */ - "NUMERIC_STAR", /* linux:522 (KEY_NUMERIC_STAR) */ - "NUMERIC_POUND", /* linux:523 (KEY_NUMERIC_POUND) */ - "KEY_NUMERIC_A", /* linux:524 (KEY_NUMERIC_A) */ - }; - - static bool GetEventName(const char* dev_type, int map, int event, bool is_button, const char** name) - { - if (!name) - return false; - - if (is_button) - { - if (event < (int)key_to_str.size()) - { - *name = key_to_str[event]; - return true; - } - return false; - } - - // assuming that PS2 axes are always mapped to PC axes - static char axis[256] = {0}; - snprintf(axis, sizeof(axis), "Axis %d", event); - *name = axis; - return true; - } - - static bool PollInput(const std::vector>& fds, std::string& dev_name, bool isaxis, int& value, bool& inverted, int& initial) - { - int event_fd = -1; - ssize_t len; - input_event event; - struct AxisValue - { - int16_t value; - bool initial; - }; - AxisValue axisVal[ABS_MAX + 1]{}; - unsigned long absbit[NBITS(ABS_MAX)]{}; - axis_correct abs_correct[ABS_MAX]{}; - - inverted = false; - - fd_set fdset; - int maxfd = -1; - - FD_ZERO(&fdset); - for (const auto& js : fds) - { - FD_SET(js.second.fd, &fdset); - if (maxfd < js.second.fd) - maxfd = js.second.fd; - } - - // wait to avoid some false positives like mouse movement - std::this_thread::sleep_for(ms(250)); - - // empty event queues - for (const auto& js : fds) - while ((len = read(js.second.fd, &event, sizeof(event))) > 0) - ; - - timeval timeout{}; - timeout.tv_sec = 5; - int result = select(maxfd + 1, &fdset, NULL, NULL, &timeout); - - if (!result) - return false; - - if (result == -1) - { - return false; - } - - for (const auto& js : fds) - { - if (FD_ISSET(js.second.fd, &fdset)) - { - event_fd = js.second.fd; - dev_name = js.first; - break; - } - } - - if (event_fd == -1) - return false; - - if (isaxis && ioctl(event_fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) - { - for (int i = 0; i < ABS_MAX; ++i) - { - if (test_bit(i, absbit)) - { - struct input_absinfo absinfo; - - if (ioctl(event_fd, EVIOCGABS(i), &absinfo) < 0) - { - continue; - } - - //TODO from SDL2, usable here? - CalcAxisCorr(abs_correct[i], absinfo); - } - } - } - - auto last = sys_clock::now(); - //Non-blocking read sets len to -1 and errno to EAGAIN if no new data - while (true) - { - auto dur = std::chrono::duration_cast(sys_clock::now() - last).count(); - if (dur > 5000) - goto error; - - if (!isaxis) - { - event_fd = -1; - for (const auto& js : fds) - { - if (FD_ISSET(js.second.fd, &fdset)) - { - event_fd = js.second.fd; - dev_name = js.first; - - break; - } - } - } - - if (event_fd > -1 && (len = read(event_fd, &event, sizeof(event))) > -1 && (len == sizeof(event))) - { - if (isaxis && event.type == EV_ABS) - { - auto& val = axisVal[event.code]; - - if (!val.initial) - { - //val.value = event.value; - val.value = AxisCorrect(abs_correct[event.code], event.value); - val.initial = true; - } - //else if (std::abs(event.value - val.value) > 1000) - else - { - int ac_val = AxisCorrect(abs_correct[event.code], event.value); - int diff = ac_val - val.value; - if (std::abs(diff) > 2047) - { - value = event.code; - inverted = (diff < 0); - initial = val.value; - break; - } - } - } - else if (!isaxis && event.type == EV_KEY) - { - if (event.value) - { - value = event.code; - break; - } - } - } - else if (errno != EAGAIN) - { - goto error; - } - else - { - while (gtk_events_pending()) - gtk_main_iteration_do(FALSE); - std::this_thread::sleep_for(ms(1)); - } - } - - return true; - - error: - return false; - } - - int EvDevPad::Configure(int port, const char* dev_type, void* data) - { - ApiCallbacks apicbs{GetEventName, EnumerateDevices, PollInput}; - int ret = 0; - if (!strcmp(dev_type, BuzzDevice::TypeName())) - ret = GtkBuzzConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs); - else if (!strcmp(dev_type, KeyboardmaniaDevice::TypeName())) - ret = GtkKeyboardmaniaConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs); - else - ret = GtkPadConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs); - return ret; - } - -#undef EVDEV_DIR - } // namespace evdev -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/evdev/evdev.cpp b/pcsx2/USB/usb-pad/evdev/evdev.cpp deleted file mode 100644 index f81ca4a509..0000000000 --- a/pcsx2/USB/usb-pad/evdev/evdev.cpp +++ /dev/null @@ -1,677 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "evdev.h" -#include -#include -#include -#include "USB/linux/util.h" - -namespace usb_pad -{ - namespace evdev - { - - // hidraw* to input/event*: - // /sys/class/hidraw/hidraw*/device/input/input*/event*/uevent - -#define NORM(x, n) (((uint32_t)(32768 + x) * n) / 0xFFFF) -#define NORM2(x, n) (((uint32_t)(32768 + x) * n) / 0x7FFF) - - bool str_ends_with(const char* str, const char* suffix) - { - if (str == nullptr || suffix == nullptr) - return false; - - size_t str_len = strlen(str); - size_t suffix_len = strlen(suffix); - - if (suffix_len > str_len) - return false; - - return 0 == strncmp(str + str_len - suffix_len, suffix, suffix_len); - } - - bool FindHidraw(const std::string& evphys, std::string& hid_dev, int* vid, int* pid) - { - int fd; - int res; - char buf[256]; - - std::stringstream str; - struct dirent* dp; - - DIR* dirp = opendir("/dev/"); - if (!dirp) - { - Console.Warning("Error opening /dev/"); - return false; - } - - while ((dp = readdir(dirp))) - { - if (strncmp(dp->d_name, "hidraw", 6) == 0) - { - - str.clear(); - str.str(""); - str << "/dev/" << dp->d_name; - std::string path = str.str(); - fd = open(path.c_str(), O_RDWR | O_NONBLOCK); - - if (fd < 0) - { - Console.Warning("Evdev: Unable to open device: %s", path.c_str()); - continue; - } - - memset(buf, 0x0, sizeof(buf)); - //res = ioctl(fd, HIDIOCGRAWNAME(256), buf); - - res = ioctl(fd, HIDIOCGRAWPHYS(sizeof(buf)), buf); - if (res < 0) - Console.Warning("HIDIOCGRAWPHYS"); - - struct hidraw_devinfo info; - memset(&info, 0x0, sizeof(info)); - - if (ioctl(fd, HIDIOCGRAWINFO, &info) < 0) - { - Console.Warning("HIDIOCGRAWINFO"); - } - else - { - if (vid) - *vid = info.vendor; - if (pid) - *pid = info.product; - } - - close(fd); - if (evphys == buf) - { - closedir(dirp); - hid_dev = path; - return true; - } - } - } - closedir(dirp); - return false; - } - -#define EVDEV_DIR "/dev/input/by-id/" - void EnumerateDevices(device_list& list) - { - int fd; - int res; - char buf[256]; - - std::stringstream str; - struct dirent* dp; - - //TODO do some caching? ioctl is "very" slow - static device_list list_cache; - - DIR* dirp = opendir(EVDEV_DIR); - if (!dirp) - { - Console.Warning("Error opening " EVDEV_DIR); - return; - } - - // get rid of unplugged devices - for (int i = 0; i < (int)list_cache.size();) - { - if (!file_exists(list_cache[i].path)) - list_cache.erase(list_cache.begin() + i); - else - i++; - } - - while ((dp = readdir(dirp))) - { - //if (strncmp(dp->d_name, "event", 5) == 0) { - if (str_ends_with(dp->d_name, "event-kbd") || str_ends_with(dp->d_name, "event-mouse") || str_ends_with(dp->d_name, "event-joystick")) - { - - str.clear(); - str.str(""); - str << EVDEV_DIR << dp->d_name; - const std::string path = str.str(); - - auto it = std::find_if(list_cache.begin(), list_cache.end(), - [&path](evdev_device& dev) { - return dev.path == path; - }); - if (it != list_cache.end()) - continue; - - fd = open(path.c_str(), O_RDWR | O_NONBLOCK); - - if (fd < 0) - { - Console.Warning("Evdev: Unable to open device: %s", path.c_str()); - continue; - } - - res = ioctl(fd, EVIOCGNAME(sizeof(buf)), buf); - if (res < 0) - Console.Warning("EVIOCGNAME"); - else - { - evdev_device dev{buf, dp->d_name, path, {}}; - res = ioctl(fd, EVIOCGID, &dev.input_id); - list_cache.push_back(dev); - } - - close(fd); - } - } - - list.assign(list_cache.begin(), list_cache.end()); - closedir(dirp); - } - - void EvDevPad::PollAxesValues(const device_data& device) - { - struct input_absinfo absinfo; - - /* Poll all axis */ - for (int i = ABS_X; i < ABS_MAX; i++) - { - absinfo = {}; - - if ((ioctl(device.cfg.fd, EVIOCGABS(i), &absinfo) >= 0) && - device.abs_correct[i].used) - { - absinfo.value = AxisCorrect(device.abs_correct[i], absinfo.value); - } - SetAxis(device, i, absinfo.value); - } - } - - void EvDevPad::SetAxis(const device_data& device, int event_code, int value) - { - int range = range_max(mType); - int code = device.axis_map[event_code] != (uint8_t)-1 ? device.axis_map[event_code] : -1 /* allow axis to be unmapped */; //event_code; - //value = AxisCorrect(mAbsCorrect[event_code], value); - - switch (code) - { - case 0x80 | JOY_STEERING: - mWheelData.steering = device.cfg.inverted[0] ? range - NORM(value, range) : NORM(value, range); - break; - case 0x80 | JOY_THROTTLE: - mWheelData.throttle = device.cfg.inverted[1] ? NORM(value, 0xFF) : 0xFF - NORM(value, 0xFF); - break; - case 0x80 | JOY_BRAKE: - mWheelData.brake = device.cfg.inverted[2] ? NORM(value, 0xFF) : 0xFF - NORM(value, 0xFF); - break; - - //TODO hatswitch mapping maybe - case ABS_HAT0X: - case ABS_HAT1X: - case ABS_HAT2X: - case ABS_HAT3X: - if (value < 0) //left usually - mWheelData.hat_horz = PAD_HAT_W; - else if (value > 0) //right - mWheelData.hat_horz = PAD_HAT_E; - else - mWheelData.hat_horz = PAD_HAT_COUNT; - break; - case ABS_HAT0Y: - case ABS_HAT1Y: - case ABS_HAT2Y: - case ABS_HAT3Y: - if (value < 0) //up usually - mWheelData.hat_vert = PAD_HAT_N; - else if (value > 0) //down - mWheelData.hat_vert = PAD_HAT_S; - else - mWheelData.hat_vert = PAD_HAT_COUNT; - break; - default: - break; - } - } - - int EvDevPad::TokenIn(uint8_t* buf, int buflen) - { - ssize_t len; - - input_event events[32]; - fd_set fds; - int maxfd; - - FD_ZERO(&fds); - maxfd = -1; - - for (auto& device : mDevices) - { - FD_SET(device.cfg.fd, &fds); - if (maxfd < device.cfg.fd) - maxfd = device.cfg.fd; - } - - struct timeval timeout; - timeout.tv_usec = timeout.tv_sec = 0; // 0 - return from select immediately - int result = select(maxfd + 1, &fds, NULL, NULL, &timeout); - - if (result <= 0) - { - return USB_RET_NAK; // If no new data, NAK it - } - - for (auto& device : mDevices) - { - if (!FD_ISSET(device.cfg.fd, &fds)) - { - continue; - } - - //Non-blocking read sets len to -1 and errno to EAGAIN if no new data - while ((len = read(device.cfg.fd, &events, sizeof(events))) > -1) - { - len /= sizeof(events[0]); - for (int i = 0; i < len; i++) - { - input_event& event = events[i]; - switch (event.type) - { - case EV_ABS: - { - if (mType == WT_BUZZ_CONTROLLER) - break; - - int value = AxisCorrect(device.abs_correct[event.code], event.value); - //if (event.code == 0) - // event.code, device.axis_map[event.code] & ~0x80, event.value, value); - SetAxis(device, event.code, value); - } - break; - case EV_KEY: - { - uint16_t button = device.btn_map[event.code]; - if (button == (uint16_t)-1 || !(button & 0x8000)) - break; - - button = button & ~0x8000; - - if (event.value) - mWheelData.buttons |= 1 << convert_wt_btn(mType, button); //on - else - mWheelData.buttons &= ~(1 << convert_wt_btn(mType, button)); //off - } - break; - case EV_SYN: //TODO useful? - { - switch (event.code) - { - case SYN_DROPPED: - //restore last good state - mWheelData = {}; - PollAxesValues(device); - break; - } - } - break; - default: - break; - } - } - - if (len <= 0) - { - break; - } - } - } - - switch (mWheelData.hat_vert) - { - case PAD_HAT_N: - switch (mWheelData.hat_horz) - { - case PAD_HAT_W: - mWheelData.hatswitch = PAD_HAT_NW; - break; - case PAD_HAT_E: - mWheelData.hatswitch = PAD_HAT_NE; - break; - default: - mWheelData.hatswitch = PAD_HAT_N; - break; - } - break; - case PAD_HAT_S: - switch (mWheelData.hat_horz) - { - case PAD_HAT_W: - mWheelData.hatswitch = PAD_HAT_SW; - break; - case PAD_HAT_E: - mWheelData.hatswitch = PAD_HAT_SE; - break; - default: - mWheelData.hatswitch = PAD_HAT_S; - break; - } - break; - default: - mWheelData.hatswitch = mWheelData.hat_horz; - break; - } - - pad_copy_data(mType, buf, mWheelData); - return buflen; - } - - int EvDevPad::TokenOut(const uint8_t* data, int len) - { - if (mUseRawFF) - { - if (mType <= WT_GT_FORCE) - { - if (data[0] == 0x8 || data[0] == 0xB) - return len; - if (data[0] == 0xF8 && - /* Allow range changes */ - !(data[1] == 0x81 || data[1] == 0x02 || data[1] == 0x03)) - return len; //don't send extended commands - } - - std::array report{0}; - - memcpy(report.data() + 1, data, report.size() - 1); - - if (!mFFData.enqueue(report)) - { - return 0; - } - return len; - } - - if (mType <= WT_GT_FORCE) - { - const ff_data* ffdata = (const ff_data*)data; - bool hires = (mType == WT_DRIVING_FORCE_PRO || mType == WT_DRIVING_FORCE_PRO_1102); - ParseFFData(ffdata, hires); - } - - return len; - } - - int EvDevPad::Open() - { - std::stringstream name; - device_list device_list; - char buf[1024]; - mWheelData = {}; - int32_t b_gain, gain, b_ac, ac; - - unsigned long keybit[NBITS(KEY_MAX)]; - unsigned long absbit[NBITS(ABS_MAX)]; - memset(keybit, 0, sizeof(keybit)); - memset(absbit, 0, sizeof(absbit)); - - // Setting to unpressed - mWheelData.steering = 0x3FF >> 1; - mWheelData.clutch = 0xFF; - mWheelData.throttle = 0xFF; - mWheelData.brake = 0xFF; - mWheelData.hatswitch = 0x8; - mWheelData.hat_horz = 0x8; - mWheelData.hat_vert = 0x8; - //memset(mAxisMap, -1, sizeof(mAxisMap)); - //memset(mBtnMap, -1, sizeof(mBtnMap)); - - //mAxisCount = 0; - //mButtonCount = 0; - //mHandle = -1; - - std::string evphys, hid_dev; - - switch (mType) - { - case WT_GENERIC: - case WT_GT_FORCE: - case WT_DRIVING_FORCE_PRO: - case WT_DRIVING_FORCE_PRO_1102: - { - if (!LoadSetting(mDevType, mPort, APINAME, N_HIDRAW_FF_PT, mUseRawFF)) - mUseRawFF = 0; - } - break; - default: - break; - } - - if (mUseRawFF) - { - // TODO could just use device fd below whose axis is mapped to steering - std::string joypath; - if (!LoadSetting(mDevType, mPort, APINAME, N_JOYSTICK, joypath)) - { - return 1; - } - - if (joypath.empty() || !file_exists(joypath)) - return 1; - - int fd = -1; - if ((fd = open(joypath.c_str(), O_RDWR | O_NONBLOCK)) < 0) - { - return 1; - } - - memset(buf, 0, sizeof(buf)); - if (ioctl(fd, EVIOCGPHYS(sizeof(buf) - 1), buf) > 0) - { - evphys = buf; - - int pid, vid; - if ((mUseRawFF = FindHidraw(evphys, hid_dev, &vid, &pid))) - { - // check if still using hidraw and run the thread - if (mUseRawFF && !mWriterThreadIsRunning) - { - if (mWriterThread.joinable()) - mWriterThread.join(); - mWriterThread = std::thread(&EvDevPad::WriterThread, this); - } - } - } - else - { - Console.Warning("EVIOCGPHYS failed"); - } - close(fd); - } - - EnumerateDevices(device_list); - - for (const auto& it : device_list) - { - bool has_mappings = false; - mDevices.push_back({}); - - struct device_data& device = mDevices.back(); - device.name = it.name; - - if ((device.cfg.fd = open(it.path.c_str(), O_RDWR | O_NONBLOCK)) < 0) - { - continue; - } - - int ret_abs = ioctl(device.cfg.fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit); - int ret_key = ioctl(device.cfg.fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit); - memset(device.axis_map, 0xFF, sizeof(device.axis_map)); - memset(device.btn_map, 0xFF, sizeof(device.btn_map)); - - if ((ret_abs < 0) && (ret_key < 0)) - { - // Probably isn't a evdev joystick - SysMessage("%s: Getting atleast some of the bits failed: %s\n", APINAME, strerror(errno)); - continue; - } - - // device.cfg.controls[0..max_buttons] - mapped buttons - // device.cfg.controls[max_buttons..etc] - mapped axes - int max_buttons = 0; - int max_axes = 0; - switch (mType) - { - case WT_BUZZ_CONTROLLER: - LoadBuzzMappings(mDevType, mPort, it.id, device.cfg); - max_buttons = 20; - break; - case WT_KEYBOARDMANIA_CONTROLLER: - max_buttons = 31; - LoadMappings(mDevType, mPort, it.id, max_buttons, 0, device.cfg); - break; - default: - max_buttons = JOY_STEERING; - max_axes = 3; - LoadMappings(mDevType, mPort, it.id, max_buttons, 3, device.cfg); - if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN_ENABLED, b_gain)) - b_gain = 1; - if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN, gain)) - gain = 100; - if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER_MANAGED, b_ac)) - b_ac = 1; - if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER, ac)) - ac = 100; - break; - } - - // Map hatswitches automatically - //FIXME has_mappings is gonna ignore hatsw only devices - for (int i = ABS_HAT0X; i <= ABS_HAT3Y; ++i) - { - device.axis_map[i] = i; - } - - // SDL2 - for (int i = 0; i < ABS_MAX; ++i) - { - if (test_bit(i, absbit)) - { - struct input_absinfo absinfo; - - if (ioctl(device.cfg.fd, EVIOCGABS(i), &absinfo) < 0) - { - continue; - } - - // convert values into 16 bit range - CalcAxisCorr(device.abs_correct[i], absinfo); - - // FIXME axes as buttons - for (int k = 0; k < max_axes; k++) - { - if (i == device.cfg.controls[k + max_buttons]) - { - has_mappings = true; - device.axis_map[i] = 0x80 | (k + JOY_STEERING); - // TODO Instead of single FF instance, create for every device with X-axis??? - // and then switch between them according to which device was used recently - if (k == 0 && !mFFdev && !mUseRawFF) - { - mFFdev = new EvdevFF(device.cfg.fd, b_gain, gain, b_ac, ac); - } - } - } - } - } - - for (int k = 0; k < max_buttons; k++) - { - auto i = device.cfg.controls[k]; - if (i >= 0 && i <= KEY_MAX) - { - has_mappings = true; - device.btn_map[i] = 0x8000 | k; - } - } - - if (!has_mappings) - { - close(device.cfg.fd); - mDevices.pop_back(); - } - } - - return 0; - } - - int EvDevPad::Close() - { - delete mFFdev; - mFFdev = nullptr; - - if (mHidHandle != -1) - { - if (mType <= WT_GT_FORCE) - { - uint8_t reset[7] = {0}; - reset[0] = 0xF3; //stop forces - if (write(mHidHandle, reset, sizeof(reset)) == -1) - { - } - } - close(mHidHandle); - } - - mHidHandle = -1; - for (auto& it : mDevices) - { - close(it.cfg.fd); - it.cfg.fd = -1; - } - mDevices.clear(); - return 0; - } - - void EvDevPad::WriterThread() - { - std::array buf; - int res; - - mWriterThreadIsRunning = true; - - while (mHidHandle != -1) - { - //if (mFFData.wait_dequeue_timed(buf, std::chrono::milliseconds(1000))) //FIXME SIGABORT :S - if (mFFData.try_dequeue(buf)) - { - res = write(mHidHandle, buf.data(), buf.size()); - if (res < 0) - { - Console.Warning("write"); - } - } - else - { // TODO skip sleep for few while cycles? - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } - - mWriterThreadIsRunning = false; - } - - } // namespace evdev -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/evdev/evdev.h b/pcsx2/USB/usb-pad/evdev/evdev.h deleted file mode 100644 index 8d267c7fd1..0000000000 --- a/pcsx2/USB/usb-pad/evdev/evdev.h +++ /dev/null @@ -1,163 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -#include "evdev-ff.h" -#include "shared.h" -#include "USB/linux/util.h" -#include "USB/readerwriterqueue/readerwriterqueue.h" -#include "common/Console.h" -//#include //gtk.h pulls in? -#include -#include -#include - -namespace usb_pad -{ - namespace evdev - { - -#define test_bit(nr, addr) \ - (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) -#define NBITS(x) ((((x)-1) / (sizeof(long) * 8)) + 1) - - void EnumerateDevices(device_list& list); - - static constexpr const char* APINAME = "evdev"; - - class EvDevPad : public Pad - { - public: - EvDevPad(int port, const char* dev_type) - : Pad(port, dev_type) - , mWriterThreadIsRunning(false) - { - } - - ~EvDevPad() { Close(); } - int Open(); - int Close(); - int TokenIn(uint8_t* buf, int len); - int TokenOut(const uint8_t* data, int len); - int Reset() { return 0; } - - static const TCHAR* Name() - { - return "Evdev"; - } - - static int Configure(int port, const char* dev_type, void* data); - - protected: - void PollAxesValues(const device_data& device); - void SetAxis(const device_data& device, int code, int value); - void WriterThread(); - - int mHidHandle = -1; - EvdevFF* mEvdevFF = nullptr; - struct wheel_data_t mWheelData - { - }; - std::vector mDevices; - int32_t mUseRawFF = 0; - std::thread mWriterThread; - std::atomic mWriterThreadIsRunning; - moodycamel::BlockingReaderWriterQueue, 32> mFFData; - }; - - template - bool GetEvdevName(const std::string& path, char (&name)[_Size]) - { - int fd = 0; - if ((fd = open(path.c_str(), O_RDONLY)) < 0) - { - Console.Warning("Cannot open %s\n", path.c_str()); - } - else - { - if (ioctl(fd, EVIOCGNAME(_Size), name) < -1) - { - Console.Warning("Cannot get controller's name\n"); - close(fd); - return false; - } - close(fd); - return true; - } - return false; - } - - static void CalcAxisCorr(axis_correct& abs_correct, struct input_absinfo absinfo) - { - int t; - // convert values into 16 bit range - if (absinfo.minimum == absinfo.maximum) - { - abs_correct.used = 0; - } - else - { - abs_correct.used = 1; - abs_correct.coef[0] = - (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat; - abs_correct.coef[1] = - (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat; - t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat); - if (t != 0) - { - abs_correct.coef[2] = - (1 << 28) / t; - } - else - { - abs_correct.coef[2] = 0; - } - } - } - - // SDL2 - // convert values into 16 bit range - static int AxisCorrect(const axis_correct& correct, int value) - { - if (correct.used) - { - value *= 2; - if (value > correct.coef[0]) - { - if (value < correct.coef[1]) - { - return 0; - } - value -= correct.coef[1]; - } - else - { - value -= correct.coef[0]; - } - value *= correct.coef[2]; - value >>= 13; - } - - /* Clamp and return */ - if (value < -32768) - return -32768; - if (value > 32767) - return 32767; - - return value; - } - - } // namespace evdev -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/evdev/shared-gtk.cpp b/pcsx2/USB/usb-pad/evdev/shared-gtk.cpp deleted file mode 100644 index 65ef9edb55..0000000000 --- a/pcsx2/USB/usb-pad/evdev/shared-gtk.cpp +++ /dev/null @@ -1,1117 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "shared.h" -#include "USB/icon_buzz_24.h" -#include "common/Console.h" - -#include -#include -#include -#include - -namespace usb_pad -{ - namespace evdev - { - - using sys_clock = std::chrono::system_clock; - using ms = std::chrono::milliseconds; - - constexpr auto CONTROL = "control"; - constexpr auto CFG = "cfg"; - - // Buttons from 0, axes after buttons - bool LoadMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, ConfigMapping& cfg) - { - std::stringstream str; - const bool use_control_names = !strcmp(dev_type, PadDevice::TypeName()); - - if (joyname.empty()) - return false; - - cfg.controls.resize(max_buttons + max_axes); - for (u32 i = 0; i < max_buttons + max_axes; i++) - { - str.clear(); - str.str(""); - if (i < max_buttons) - { - str << "button_"; - if (use_control_names && i < (u32)countof(JoystickMapNames)) - str << JoystickMapNames[i]; - else - str << i; - } - else - { - str << "axis_"; - u32 axis = i - max_buttons; - if (use_control_names && (JOY_STEERING + axis) < (u32)countof(JoystickMapNames)) - str << JoystickMapNames[JOY_STEERING + axis]; - else - str << axis; - } - - const std::string& name = str.str(); - int32_t var; - if (LoadSetting(dev_type, port, joyname, name.c_str(), var)) - cfg.controls[i] = var; - else - cfg.controls[i] = -1; - } - - for (int i = 0; i < 3; i++) - { - str.clear(); - str.str(""); - str << "inverted_"; - if (use_control_names) - str << JoystickMapNames[JOY_STEERING + i]; - else - str << i; - - { - const std::string& name = str.str(); - if (!LoadSetting(dev_type, port, joyname, name.c_str(), cfg.inverted[i])) - cfg.inverted[i] = 0; - } - - str.clear(); - str.str(""); - str << "initial_"; - if (use_control_names) - str << JoystickMapNames[JOY_STEERING + i]; - else - str << i; - - { - const std::string& name = str.str(); - if (!LoadSetting(dev_type, port, joyname, name.c_str(), cfg.initial[i])) - cfg.initial[i] = 0; - } - } - return true; - } - - bool SaveMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, const ConfigMapping& cfg) - { - if (joyname.empty() || cfg.controls.size() != max_buttons + max_axes) - return false; - - RemoveSection(dev_type, port, joyname); - std::stringstream str; - const bool use_control_names = !strcmp(dev_type, PadDevice::TypeName()); - bool has_axes = false; - - for (u32 i = 0; i < max_buttons + max_axes; i++) - { - str.clear(); - str.str(""); - if (i < max_buttons) - { - str << "button_"; - if (use_control_names && i < (u32)countof(JoystickMapNames)) - str << JoystickMapNames[i]; - else - str << i; - } - else - { - str << "axis_"; - u32 axis = i - max_buttons; - if (use_control_names && (JOY_STEERING + axis) < (u32)countof(JoystickMapNames)) - str << JoystickMapNames[JOY_STEERING + axis]; - else - str << axis; - } - - const std::string& name = str.str(); - if (cfg.controls[i] >= 0) - { - if (!SaveSetting(dev_type, port, joyname, name.c_str(), static_cast(cfg.controls[i]))) - return false; - if (i >= max_buttons) - has_axes = true; - } - } - - for (u32 i = 0; i < 3 && has_axes; i++) - { - str.clear(); - str.str(""); - str << "inverted_"; - if (use_control_names) - str << JoystickMapNames[JOY_STEERING + i]; - else - str << i; - - { - const std::string& name = str.str(); - if (!SaveSetting(dev_type, port, joyname, name.c_str(), cfg.inverted[i])) - return false; - } - - str.clear(); - str.str(""); - str << "initial_"; - if (use_control_names) - str << JoystickMapNames[JOY_STEERING + i]; - else - str << i; - - { - const std::string& name = str.str(); - if (!SaveSetting(dev_type, port, joyname, name.c_str(), cfg.initial[i])) - return false; - } - } - return true; - } - - bool LoadBuzzMappings(const char* dev_type, int port, const std::string& joyname, ConfigMapping& cfg) - { - std::stringstream str; - - if (joyname.empty()) - return false; - - int j = 0; - - cfg.controls.resize(countof(buzz_map_names) * 4); - for (auto& i : cfg.controls) - { - str.str(""); - str.clear(); - str << "map_" << buzz_map_names[j % 5] << "_" << (j / 5); - const std::string& name = str.str(); - int32_t var; - if (LoadSetting(dev_type, port, joyname, name.c_str(), var)) - i = var; - else - i = -1; - j++; - } - return true; - } - - bool SaveBuzzMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg) - { - if (joyname.empty()) - return false; - - RemoveSection(dev_type, port, joyname); - std::stringstream str; - - const size_t c = countof(buzz_map_names); - for (size_t i = 0; i < cfg.controls.size(); i++) - { - str.str(""); - str.clear(); - str << "map_" << buzz_map_names[i % c] << "_" << (i / c); - const std::string& name = str.str(); - if (cfg.controls[i] >= 0 && !SaveSetting(dev_type, port, joyname, name.c_str(), static_cast(cfg.controls[i]))) - return false; - } - return true; - } - - static void refresh_store(ConfigData* cfg) - { - GtkTreeIter iter; - std::string name; - - gtk_list_store_clear(cfg->store); - for (auto& it : cfg->jsconf) - { - for (size_t i = 0; i < it.second.controls.size(); i++) - { - if (it.second.controls[i] < 0) - continue; - - const char* pc_name = "Unknown"; - bool is_button = (i < cfg->max_buttons); - cfg->cb->get_event_name(cfg->dev_type, i, it.second.controls[i], is_button, &pc_name); - - gtk_list_store_append(cfg->store, &iter); - - if (!strcmp(cfg->dev_type, BuzzDevice::TypeName())) - { - std::stringstream ss; - ss << (1 + i / countof(buzz_map_names)); - ss << " "; - ss << buzz_map_names[i % countof(buzz_map_names)]; - name = ss.str(); - } - else if (!strcmp(cfg->dev_type, PadDevice::TypeName())) - name = JoystickMapNames[i]; - else if (!strcmp(cfg->dev_type, KeyboardmaniaDevice::TypeName())) - name = kbdmania_key_labels[i]; - else - { - std::stringstream ss; - if (is_button) - ss << "Button " << i; - else - ss << "Axis " << (i - cfg->max_buttons); - name = ss.str(); - } - - gtk_list_store_set(cfg->store, &iter, - COL_NAME, it.first.c_str(), - COL_PS2, name.c_str(), - COL_PC, pc_name, - COL_BINDING, i, - -1); - } - } - } - - static void joystick_changed(GtkComboBox* widget, gpointer data) - { - gint idx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - //int port = reinterpret_cast(data); - ConfigData* cfg = reinterpret_cast(g_object_get_data(G_OBJECT(widget), CFG)); - - if (!cfg) - return; - - if (idx > -1) - cfg->js_iter = (cfg->joysticks.begin() + idx); - } - - static void button_clicked(GtkWidget* widget, gpointer data) - { - u32 control = reinterpret_cast(g_object_get_data(G_OBJECT(widget), CONTROL)); - ConfigData* cfg = reinterpret_cast(g_object_get_data(G_OBJECT(widget), CFG)); - if (!cfg) - return; - - int value, initial = 0; - std::string dev_name; - bool inverted = false; - bool is_axis = (control >= cfg->max_buttons); - - gtk_label_set_text(GTK_LABEL(cfg->label), "Polling for input for 5 seconds..."); - - // let label change its text - while (gtk_events_pending()) - gtk_main_iteration_do(FALSE); - - if (cfg->cb->poll(cfg->jsconf, dev_name, is_axis, value, inverted, initial)) - { - auto it = std::find_if(cfg->jsconf.begin(), cfg->jsconf.end(), - [&dev_name](MappingPair& i) -> bool { - return i.first == dev_name; - }); - - if (it != cfg->jsconf.end() && control < (u32)it->second.controls.size()) - { - it->second.controls[control] = value; - if (is_axis && control - cfg->max_buttons < countof(it->second.inverted)) - { - it->second.inverted[control - cfg->max_buttons] = inverted; - it->second.initial[control - cfg->max_buttons] = initial; - } - refresh_store(cfg); - } - } - gtk_label_set_text(GTK_LABEL(cfg->label), ""); - } - - // save references to row paths, automatically updated when store changes - static void view_selected_foreach_func(GtkTreeModel* model, - GtkTreePath* path, GtkTreeIter* iter, gpointer userdata) - { - GList** rr_list = (GList**)userdata; - GtkTreeRowReference* rowref; - rowref = gtk_tree_row_reference_new(model, path); - *rr_list = g_list_append(*rr_list, rowref); - } - - static void view_remove_binding(GtkTreeModel* model, - GtkTreeIter* iter, ConfigData* cfg) - { - gchar* dev_name; - int binding; - - gtk_tree_model_get(model, iter, COL_NAME, &dev_name, COL_BINDING, &binding, -1); - - auto& js = cfg->jsconf; - auto it = std::find_if(js.begin(), js.end(), - [&dev_name](MappingPair i) { - return i.first == dev_name; - }); - if (it != js.end()) - { - it->second.controls[binding] = (uint16_t)-1; - } - gtk_list_store_remove(GTK_LIST_STORE(model), iter); - //refresh_store(cfg); - - g_free(dev_name); - } - - static void clear_binding_clicked(GtkWidget* widget, gpointer data) - { - GtkTreeModel* model = nullptr; - GList* rr_list = nullptr; - GList* node = nullptr; - - ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG); - GtkTreeSelection* sel = gtk_tree_view_get_selection(cfg->treeview); - - gtk_tree_selection_selected_foreach(sel, view_selected_foreach_func, &rr_list); - - GList* list = gtk_tree_selection_get_selected_rows(sel, &model); - // remove rows from store pointed to by row references - for (node = g_list_first(rr_list); node != nullptr; node = node->next) - { - GtkTreePath* path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)node->data); - if (path) - { - GtkTreeIter iter; - if (gtk_tree_model_get_iter(model, &iter, path)) - { - view_remove_binding(model, &iter, cfg); - } - } - } - - g_list_free_full(rr_list, (GDestroyNotify)gtk_tree_row_reference_free); - g_list_free_full(list, (GDestroyNotify)gtk_tree_path_free); - } - - static void clear_all_clicked(GtkWidget* widget, gpointer data) - { - ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG); - for (auto& it : cfg->jsconf) - it.second.controls.assign(it.second.controls.size(), -1); - refresh_store(cfg); - } - - static void checkbox_toggled(GtkToggleButton* widget, gpointer data) - { - gboolean* val = reinterpret_cast(data); - if (val) - { - *val = (bool)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - } - } - - static GtkWidget* make_dialog(GtkWindow* parent, const std::string& title, int w = 1200, int h = 700) - { - auto dlg = gtk_dialog_new_with_buttons( - title.c_str(), parent, GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE); - gtk_window_set_default_size(GTK_WINDOW(dlg), w, h); - return dlg; - } - - static void create_panes(GtkWidget* container, GtkWidget*& left_vbox, GtkWidget*& right_vbox) - { - left_vbox = gtk_vbox_new(FALSE, 5); - right_vbox = gtk_vbox_new(FALSE, 15); - -#if 0 - GtkWidget* paned = gtk_hpaned_new(); - gtk_container_add(GTK_CONTAINER(container), paned); - gtk_paned_add1(GTK_PANED(paned), left_vbox); - - GtkWidget* sc_win = gtk_scrolled_window_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(sc_win), right_vbox); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_paned_add2(GTK_PANED(paned), sc_win); -#else - GtkWidget* hbox = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(container), hbox); - gtk_box_pack_start(GTK_BOX(hbox), left_vbox, TRUE, TRUE, 5); - gtk_box_pack_start(GTK_BOX(hbox), right_vbox, TRUE, TRUE, 5); -#endif -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_widget_set_vexpand(left_vbox, TRUE); - gtk_widget_set_valign(right_vbox, GTK_ALIGN_START); -#endif - } - - static GtkWidget* make_mappings_treeview(int port, ConfigData& cfg, GtkWidget* container) - { - GtkWidget* button; - auto treeview = gtk_tree_view_new(); - cfg.treeview = GTK_TREE_VIEW(treeview); - auto selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); - - GtkCellRenderer* render = gtk_cell_renderer_text_new(); - - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), - -1, "Name", render, "text", COL_NAME, NULL); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), - -1, "PS2", render, "text", COL_PS2, NULL); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), - -1, "PC", render, "text", COL_PC, NULL); - - gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(treeview), 0); - - gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0), TRUE); - gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 1), TRUE); - gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 2), TRUE); - - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(cfg.store)); - g_object_unref(GTK_TREE_MODEL(cfg.store)); //treeview has its own ref - - GtkWidget* scwin = gtk_scrolled_window_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(scwin), treeview); - gtk_widget_set_size_request(GTK_WIDGET(scwin), 200, 100); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_box_pack_start(GTK_BOX(container), scwin, TRUE, TRUE, 5); - - button = gtk_button_new_with_label("Clear binding"); - gtk_box_pack_start(GTK_BOX(container), button, FALSE, FALSE, 5); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_binding_clicked), reinterpret_cast(port)); - - button = gtk_button_new_with_label("Clear All"); - gtk_box_pack_start(GTK_BOX(container), button, FALSE, FALSE, 5); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_all_clicked), reinterpret_cast(port)); - return treeview; - } - - static void load_devices_mappings(ConfigData& cfg, const int port, ApiCallbacks& apicbs) - { - int fd; - apicbs.populate(cfg.joysticks); - - cfg.js_iter = cfg.joysticks.end(); - cfg.label = gtk_label_new(""); - cfg.store = gtk_list_store_new(NUM_COLS, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); - cfg.cb = &apicbs; - - for (const auto& it : cfg.joysticks) - { - if ((fd = open(it.path.c_str(), O_RDONLY | O_NONBLOCK)) < 0) - { - Console.Warning("USB: failed to open '%s'", it.path.c_str()); - continue; - } - - ConfigMapping c(fd); - LoadMappings(cfg.dev_type, port, it.id, cfg.max_buttons, cfg.max_axes, c); - cfg.jsconf.push_back(std::make_pair(it.id, c)); - } - - refresh_store(&cfg); - } - - int GtkPadConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs) - { - GtkWidget *right_vbox, *left_vbox; - - ConfigData cfg{}; - cfg.dev_type = dev_type; - cfg.max_axes = 3; - cfg.max_buttons = JOY_STEERING; // 16 - load_devices_mappings(cfg, port, apicbs); - - std::string path; - LoadSetting(dev_type, port, apiname, N_JOYSTICK, path); - - cfg.use_hidraw_ff_pt = false; - bool is_evdev = (strncmp(apiname, "evdev", 5) == 0); - if (is_evdev) - { - LoadSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt); - } - - // --------------------------- - const std::string title = std::string(port ? "Player One " : "Player Two ") + apititle; - GtkWidget* dlg = make_dialog(parent, title); - - // --------------------------- - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - create_panes(dlg_area_box, left_vbox, right_vbox); - make_mappings_treeview(port, cfg, left_vbox); - - // --------------------------- - - // Remapping - { - GtkWidget* table = gtk_table_new(5, 7, TRUE); - gtk_container_add(GTK_CONTAINER(right_vbox), table); - //GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default - GtkAttachOptions opt = (GtkAttachOptions)(GTK_FILL); - - const char* button_labels[] = { - "L2", - "L1 / L", - "R2", - "R1 / R / Orange", - "Left", - "Up", - "Right", - "Down", - "Square / X / Green", - "Cross / A / Blue", - "Circle / B / Red", - "Triangle / Y / Yellow", - "Select", - "Start", - }; - - const Point button_pos[] = { - {1, 0, JOY_L2}, - {1, 1, JOY_L1}, - {5, 0, JOY_R2}, - {5, 1, JOY_R1}, - {0, 3, JOY_LEFT}, - {1, 2, JOY_UP}, - {2, 3, JOY_RIGHT}, - {1, 4, JOY_DOWN}, - {4, 3, JOY_SQUARE}, - {5, 4, JOY_CROSS}, - {6, 3, JOY_CIRCLE}, - {5, 2, JOY_TRIANGLE}, - {3, 3, JOY_SELECT}, - {3, 2, JOY_START}, - }; - - for (int i = 0; i < (int)countof(button_labels); i++) - { - GtkWidget* button = gtk_button_new_with_label(button_labels[i]); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(button_pos[i].type)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - - gtk_table_attach(GTK_TABLE(table), button, - 0 + button_pos[i].x, 1 + button_pos[i].x, - 0 + button_pos[i].y, 1 + button_pos[i].y, - opt, opt, 5, 1); - } - - GtkWidget* hbox = gtk_hbox_new(false, 5); - gtk_container_add(GTK_CONTAINER(right_vbox), hbox); - - GtkWidget* button = gtk_button_new_with_label("Steering"); - gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(JOY_STEERING)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - - button = gtk_button_new_with_label("Throttle"); - gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(JOY_THROTTLE)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - - button = gtk_button_new_with_label("Brake"); - gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(JOY_BRAKE)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - - gtk_box_pack_start(GTK_BOX(right_vbox), cfg.label, TRUE, TRUE, 5); - } - GtkWidget* ro_frame = gtk_frame_new("Force feedback"); - gtk_box_pack_start(GTK_BOX(right_vbox), ro_frame, TRUE, FALSE, 5); - - //GtkWidget *frame_vbox = gtk_vbox_new (FALSE, 5); - //gtk_container_add (GTK_CONTAINER (ro_frame), frame_vbox); - - const char* labels_buff[][2] = {{"Set gain", "Gain"}, {"Managed by game", "Autocenter strength"}}; - const char* ff_var_name[][2] = {{N_GAIN_ENABLED, N_GAIN}, {N_AUTOCENTER_MANAGED, N_AUTOCENTER}}; - GtkWidget* ff_scales[2]; - int32_t ff_enabled[2]; - - GtkWidget* table = gtk_table_new(3, 2, TRUE); - gtk_container_add(GTK_CONTAINER(ro_frame), table); - gtk_table_set_homogeneous(GTK_TABLE(table), FALSE); - GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default - - for (int i = 0; i < 2; i++) - { - if (LoadSetting(dev_type, port, apiname, ff_var_name[i][0], ff_enabled[i])) - ff_enabled[i] = !!ff_enabled[i]; - else - ff_enabled[i] = 1; - - GtkWidget* chk_btn = gtk_check_button_new_with_label(labels_buff[i][0]); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_btn), (gboolean)ff_enabled[i]); - g_signal_connect(G_OBJECT(chk_btn), "toggled", G_CALLBACK(checkbox_toggled), reinterpret_cast(&ff_enabled[i])); - gtk_table_attach(GTK_TABLE(table), chk_btn, - 2, 3, - 0 + i, 1 + i, - GTK_FILL, GTK_SHRINK, 5, 1); - - GtkWidget* label = gtk_label_new(labels_buff[i][1]); - gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, - 0, 1, - 0 + i, 1 + i, - GTK_FILL, GTK_SHRINK, 5, 1); - - //ff_scales[i] = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 100, 1); - ff_scales[i] = gtk_hscale_new_with_range(0, 100, 1); - for (int v = 0; v <= 100; v += 10) - gtk_scale_add_mark(GTK_SCALE(ff_scales[i]), v, GTK_POS_BOTTOM, nullptr); - gtk_table_attach(GTK_TABLE(table), ff_scales[i], - 1, 2, - 0 + i, 1 + i, - opt, opt, 5, 1); - - int32_t var; - if (LoadSetting(dev_type, port, apiname, ff_var_name[i][1], var)) - { - var = std::min(100, std::max(0, var)); - gtk_range_set_value(GTK_RANGE(ff_scales[i]), var); - } - else - gtk_range_set_value(GTK_RANGE(ff_scales[i]), 100); - } - - if (is_evdev) - { - ro_frame = gtk_frame_new("Logitech wheel force feedback pass-through using hidraw"); - gtk_box_pack_start(GTK_BOX(right_vbox), ro_frame, FALSE, FALSE, 5); - - GtkWidget* frame_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ro_frame), frame_vbox); - - GtkWidget* chk_btn = gtk_check_button_new_with_label("Enable"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_btn), (gboolean)cfg.use_hidraw_ff_pt); - //g_object_set_data(G_OBJECT(chk_btn), CFG, &cfg); - g_signal_connect(G_OBJECT(chk_btn), "toggled", G_CALLBACK(checkbox_toggled), reinterpret_cast(&cfg.use_hidraw_ff_pt)); - gtk_box_pack_start(GTK_BOX(frame_vbox), chk_btn, FALSE, FALSE, 5); - - GtkWidget* rs_cb = new_combobox("Device:", frame_vbox, true); - - const std::vector whitelist{PAD_LG_FFB_WHITELIST}; - int idx = 0, sel_idx = 0; - for (auto& it : cfg.joysticks) - { - if (!(it.input_id.vendor == PAD_VID && std::find(whitelist.begin(), whitelist.end(), it.input_id.product) != whitelist.end())) - continue; - - std::stringstream str; - str << it.name; - if (!it.id.empty()) - str << " [" << it.id << "]"; - - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), str.str().c_str()); - if (path == it.path) - sel_idx = idx; - idx++; - } - - g_object_set_data(G_OBJECT(rs_cb), CFG, &cfg); - g_signal_connect(G_OBJECT(rs_cb), "changed", G_CALLBACK(joystick_changed), reinterpret_cast(port)); - gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), sel_idx); - } - // --------------------------- - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - - int ret = RESULT_OK; - if (result == GTK_RESPONSE_OK) - { - if (cfg.js_iter != cfg.joysticks.end()) - { - if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->path)) - ret = RESULT_FAILED; - } - - for (auto& it : cfg.jsconf) - SaveMappings(dev_type, port, it.first, cfg.max_buttons, cfg.max_axes, it.second); - - if (is_evdev) - { - SaveSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt); - } - for (int i = 0; i < 2; i++) - { - SaveSetting(dev_type, port, apiname, ff_var_name[i][0], ff_enabled[i]); - int val = gtk_range_get_value(GTK_RANGE(ff_scales[i])); - SaveSetting(dev_type, port, apiname, ff_var_name[i][1], val); - } - } - else - ret = RESULT_CANCELED; - - for (auto& it : cfg.jsconf) - close(it.second.fd); - - gtk_widget_destroy(dlg); - return ret; - } - - GtkWidget* make_color_icon(uint32_t rgb) - { - GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 24, 24); - guchar* data = gdk_pixbuf_get_pixels(pixbuf); - - for (size_t i = 0; i < 24 * 24; i++) - { - data[i * 4 + 0] = rgb & 0xFF; - data[i * 4 + 1] = (rgb >> 8) & 0xFF; - data[i * 4 + 2] = (rgb >> 16) & 0xFF; - data[i * 4 + 3] = icon_buzz_24[i]; - } - - GtkWidget* w = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(G_OBJECT(pixbuf)); - return w; - } - - int GtkBuzzConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs) - { - GtkWidget *main_hbox, *right_vbox, *left_vbox; - - int fd; - ConfigData cfg{}; - - apicbs.populate(cfg.joysticks); - - cfg.js_iter = cfg.joysticks.end(); - cfg.label = gtk_label_new(""); - cfg.store = gtk_list_store_new(NUM_COLS, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); - cfg.cb = &apicbs; - cfg.dev_type = dev_type; - cfg.max_axes = 0; - cfg.max_buttons = 20; - - for (const auto& it : cfg.joysticks) - { - if ((fd = open(it.path.c_str(), O_RDONLY | O_NONBLOCK)) < 0) - { - continue; - } - - ConfigMapping c; - c.fd = fd; - LoadBuzzMappings(cfg.dev_type, port, it.id, c); - cfg.jsconf.push_back(std::make_pair(it.id, c)); - } - - refresh_store(&cfg); - - // --------------------------- - const std::string title = std::string("Buzz ") + apititle; - GtkWidget* dlg = make_dialog(parent, title); - - // --------------------------- - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - - main_hbox = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(dlg_area_box), main_hbox); - - left_vbox = gtk_vbox_new(FALSE, 5); - right_vbox = gtk_vbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(main_hbox), left_vbox, TRUE, TRUE, 5); - gtk_box_pack_start(GTK_BOX(main_hbox), right_vbox, TRUE, TRUE, 5); - - make_mappings_treeview(port, cfg, left_vbox); - -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_widget_set_vexpand(left_vbox, TRUE); -#endif - - // --------------------------- - - // Remapping - { - GtkWidget* table = gtk_table_new(5, 4, TRUE); - gtk_container_add(GTK_CONTAINER(right_vbox), table); - GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default - - static const char* button_labels[]{ - "Red", - "Blue", - "Orange", - "Green", - "Yellow", - }; - - static const Buzz buzz_btns[]{ - BUZZ_RED, - BUZZ_BLUE, - BUZZ_ORANGE, - BUZZ_GREEN, - BUZZ_YELLOW, - }; - - static const uint32_t icon_colors[]{ - 0x0000FF, - 0xFF0000, - 0x0080FF, - 0x00FF00, - 0x00FFFF, - }; - - for (int j = 0; j < 4; j++) - { - for (int i = 0; i < (int)countof(button_labels); i++) - { - GtkWidget* button = gtk_button_new_with_label(button_labels[i]); - - GtkWidget* icon = make_color_icon(icon_colors[i]); - gtk_button_set_image(GTK_BUTTON(button), icon); - gtk_button_set_image_position(GTK_BUTTON(button), GTK_POS_LEFT); - - GList* children = gtk_container_get_children(GTK_CONTAINER(button)); - - //Gtk 3.16+ - //gtk_label_set_xalign (GTK_WIDGET(children), 0.0) - - //gtk_misc_set_alignment (GTK_MISC (children->data), 0.0, 0.5); - if (GTK_IS_ALIGNMENT(children->data)) - gtk_alignment_set(GTK_ALIGNMENT(children->data), 0.0f, 0.5f, 0.2f, 0.f); - - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(j * countof(buzz_btns) + buzz_btns[i])); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - - gtk_table_attach(GTK_TABLE(table), button, - j, 1 + j, - i + 1, 2 + i, - opt, opt, 5, 1); - } - - gtk_table_attach(GTK_TABLE(table), gtk_label_new("Player 1"), - 0, 1, 0, 1, opt, opt, 5, 1); - gtk_table_attach(GTK_TABLE(table), gtk_label_new("Player 2"), - 1, 2, 0, 1, opt, opt, 5, 1); - gtk_table_attach(GTK_TABLE(table), gtk_label_new("Player 3"), - 2, 3, 0, 1, opt, opt, 5, 1); - gtk_table_attach(GTK_TABLE(table), gtk_label_new("Player 4"), - 3, 4, 0, 1, opt, opt, 5, 1); - } - - GtkWidget* hbox = gtk_hbox_new(false, 5); - gtk_container_add(GTK_CONTAINER(right_vbox), hbox); - - gtk_box_pack_start(GTK_BOX(right_vbox), cfg.label, TRUE, TRUE, 5); - } - - // --------------------------- - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - - int ret = RESULT_OK; - if (result == GTK_RESPONSE_OK) - { - if (cfg.js_iter != cfg.joysticks.end()) - { - if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->path)) - ret = RESULT_FAILED; - } - - for (auto& it : cfg.jsconf) - SaveBuzzMappings(dev_type, port, it.first, it.second); - } - else - ret = RESULT_CANCELED; - - for (auto& it : cfg.jsconf) - close(it.second.fd); - - gtk_widget_destroy(dlg); - return ret; - } - - int GtkKeyboardmaniaConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs) - { - GtkWidget *right_vbox, *left_vbox; - - ConfigData cfg{}; - cfg.dev_type = dev_type; - cfg.max_buttons = 31; - load_devices_mappings(cfg, port, apicbs); - - // --------------------------- - const std::string title = std::string("Keyboardmania ") + apititle; - GtkWidget* dlg = make_dialog(parent, title); - - // --------------------------- - GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); - create_panes(dlg_area_box, left_vbox, right_vbox); - make_mappings_treeview(port, cfg, left_vbox); - - // --------------------------- - // Remapping - { - GtkWidget* table = gtk_table_new(5, 14, TRUE); - gtk_container_add(GTK_CONTAINER(right_vbox), table); - GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_widget_set_halign(table, GTK_ALIGN_START); -#endif - - struct keys - { - u32 index; - bool sharp; - }; - - constexpr keys keys[]{ - {0, false}, - {1, true}, - {2, false}, - {3, true}, - {4, false}, - {5, false}, - {6, true}, - //{"padding", 7}, - {8, false}, - {9, true}, - {10, false}, - {11, true}, - {12, false}, - {13, false}, - //{"Select", 14}, - //{"padding", 15}, - {16, true}, - {17, false}, - {18, true}, - {19, false}, - {20, false}, - {21, true}, - //{"Start", 22}, - //{"padding", 23}, - {24, false}, - {25, true}, - {26, false}, - {27, true}, - {28, false}, - //{"Up", 29}, - //{"Down", 30}, - }; - - int attached = 0; - int voffset = 0; - for (auto& key : keys) - { - GtkWidget* button = gtk_button_new_with_label(kbdmania_key_labels[key.index]); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(key.index)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - - // split into 2-by-2 rows - if (attached > 6) - { - voffset = 2; - attached = 0; - } - - if (!key.sharp) - { - gtk_table_attach(GTK_TABLE(table), button, - attached * 2, 2 + attached * 2, - 1 + voffset, 2 + voffset, - opt, opt, 5, 1); - attached++; - } - else - gtk_table_attach(GTK_TABLE(table), button, - attached * 2 - 1, attached * 2 + 2 - 1, - 0 + voffset, 1 + voffset, - opt, opt, 5, 1); - } - - GtkWidget *button, *frame_box, *frame; - GtkWidget* frame_container = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(right_vbox), frame_container); -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_widget_set_valign(frame_container, GTK_ALIGN_START); -#endif - - frame = gtk_frame_new("Buttons"); - { - frame_box = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(frame), frame_box); - gtk_box_pack_start(GTK_BOX(frame_container), frame, FALSE, FALSE, 5); - - button = gtk_button_new_with_label("Start"); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(22)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5); - - button = gtk_button_new_with_label("Select"); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(14)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5); - } - - frame = gtk_frame_new("Wheel"); - { - frame_box = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(frame), frame_box); - gtk_box_pack_start(GTK_BOX(frame_container), frame, FALSE, FALSE, 5); - - button = gtk_button_new_with_label("Up"); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(29)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5); - - button = gtk_button_new_with_label("Down"); - g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast(port)); - g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast(30)); - g_object_set_data(G_OBJECT(button), CFG, &cfg); - gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5); - } - } - - gtk_box_pack_start(GTK_BOX(right_vbox), cfg.label, TRUE, TRUE, 5); - - // --------------------------- - gtk_widget_show_all(dlg); - gint result = gtk_dialog_run(GTK_DIALOG(dlg)); - - int ret = RESULT_OK; - if (result == GTK_RESPONSE_OK) - { - if (cfg.js_iter != cfg.joysticks.end()) - { - if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->path)) - ret = RESULT_FAILED; - } - - for (auto& it : cfg.jsconf) - SaveMappings(dev_type, port, it.first, cfg.max_buttons, 0, it.second); - } - else - ret = RESULT_CANCELED; - - for (auto& it : cfg.jsconf) - close(it.second.fd); - - gtk_widget_destroy(dlg); - return ret; - } - - } // namespace evdev -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/evdev/shared.h b/pcsx2/USB/usb-pad/evdev/shared.h deleted file mode 100644 index 3f0fe1ba65..0000000000 --- a/pcsx2/USB/usb-pad/evdev/shared.h +++ /dev/null @@ -1,214 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -#include -#include -#include "common/Pcsx2Types.h" -#include "USB/gtk.h" -#include "USB/usb-pad/padproxy.h" -#include "USB/configuration.h" - -#define N_HIDRAW_FF_PT "hidraw_ff_pt" -#define N_GAIN_ENABLED "gain_enabled" -#define N_GAIN "gain" -#define N_AUTOCENTER "autocenter" -#define N_AUTOCENTER_MANAGED "ac_managed" - -struct evdev_device -{ - std::string name; - std::string id; - std::string path; - struct { - uint16_t bustype; - uint16_t vendor; - uint16_t product; - uint16_t version; - } input_id; -}; - -typedef std::vector device_list; - -namespace usb_pad -{ - namespace evdev - { - - enum - { - COL_NAME = 0, - COL_PS2, - COL_PC, - COL_BINDING, - NUM_COLS - }; - - // Keep in sync with PS2Buttons enum - enum JoystickMap - { - JOY_CROSS = 0, - JOY_SQUARE, - JOY_CIRCLE, - JOY_TRIANGLE, - JOY_R1, - JOY_L1, - JOY_R2, - JOY_L2, - JOY_SELECT, - JOY_START, - JOY_R3, - JOY_L3, //order, afaik not used on any PS2 wheel anyway - JOY_DOWN, - JOY_LEFT, - JOY_UP, - JOY_RIGHT, - JOY_STEERING, - JOY_THROTTLE, - JOY_BRAKE, - JOY_MAPS_COUNT - }; - - constexpr const char* JoystickMapNames[]{ - "cross", - "square", - "circle", - "triangle", - "r1", - "l1", - "r2", - "l2", - "select", - "start", - "r3", - "l3", - "down", - "left", - "up", - "right", - "steering", - "throttle", - "brake", - }; - - constexpr const char* buzz_map_names[]{ - "red", - "yellow", - "green", - "orange", - "blue", - }; - - constexpr const char* kbdmania_key_labels[]{ - "C 1", - "C# 1", - "D 1", - "D# 1", - "E 1", - "F 1", - "F# 1", - "", - "G 1", - "G# 1", - "A 1", - "A# 1", - "B 1", - "C 2", - "Select", - "", - "C# 2", - "D 2", - "D# 2", - "E 2", - "F 2", - "F# 2", - "Start", - "", - "G 2", - "G# 2", - "A 2", - "A# 2", - "B 2", - "Up", - "Down", - }; - - struct Point - { - int x; - int y; - JoystickMap type; - }; - - struct ConfigMapping - { - std::vector controls; - int inverted[3]; - int initial[3]; - int fd = -1; - - ConfigMapping() = default; - ConfigMapping(int fd_) - : fd(fd_) - { - } - }; - - struct ApiCallbacks - { - bool (*get_event_name)(const char* dev_type, int map, int event, bool is_button, const char** name); - void (*populate)(device_list& jsdata); - bool (*poll)(const std::vector>& jsconf, std::string& dev_name, bool isaxis, int& value, bool& inverted, int& initial); - }; - - typedef std::pair MappingPair; - struct ConfigData - { - std::vector jsconf; - device_list joysticks; - device_list::const_iterator js_iter; - GtkWidget* label; - GtkListStore* store; - GtkTreeView* treeview; - ApiCallbacks* cb; - int use_hidraw_ff_pt; - const char* dev_type; - u32 max_axes, max_buttons; - }; - - struct axis_correct - { - int used; - int coef[3]; - }; - - struct device_data - { - ConfigMapping cfg; - std::string name; - uint8_t axis_map[ABS_MAX + 1]; - uint16_t btn_map[KEY_MAX + 1]; - struct axis_correct abs_correct[ABS_MAX]; - }; - - int GtkPadConfigure(int port, const char* dev_type, const char* title, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs); - int GtkBuzzConfigure(int port, const char* dev_type, const char* title, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs); - int GtkKeyboardmaniaConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs); - bool LoadMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, ConfigMapping& cfg); - bool SaveMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, const ConfigMapping& cfg); - bool LoadBuzzMappings(const char* dev_type, int port, const std::string& joyname, ConfigMapping& cfg); - bool SaveBuzzMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg); - } // namespace evdev -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/padproxy.h b/pcsx2/USB/usb-pad/padproxy.h deleted file mode 100644 index 8e825e32d4..0000000000 --- a/pcsx2/USB/usb-pad/padproxy.h +++ /dev/null @@ -1,88 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef PADPROXY_H -#define PADPROXY_H -#include -#include -#include -#include -#include -#include -#include "usb-pad.h" -#include "USB/helpers.h" -#include "USB/deviceproxy.h" - -namespace usb_pad -{ - - class PadError : public std::runtime_error - { - public: - PadError(const char* msg) - : std::runtime_error(msg) - { - } - virtual ~PadError() {} - }; - - class PadProxyBase : public ProxyBase - { - PadProxyBase(const PadProxyBase&) = delete; - - public: - PadProxyBase() {} - PadProxyBase(const std::string& name); - virtual Pad* CreateObject(int port, const char* dev_type) const = 0; - }; - - template - class PadProxy : public PadProxyBase - { - PadProxy(const PadProxy&) = delete; - - public: - PadProxy() { } - ~PadProxy() { } - Pad* CreateObject(int port, const char* dev_type) const - { - try - { - return new T(port, dev_type); - } - catch (PadError& err) - { - (void)err; - return nullptr; - } - } - virtual const TCHAR* Name() const - { - return T::Name(); - } - virtual int Configure(int port, const char* dev_type, void* data) - { - return T::Configure(port, dev_type, data); - } - }; - - class RegisterPad : public RegisterProxy - { - public: - static void Register(); - }; - -} // namespace usb_pad -#endif diff --git a/pcsx2/USB/usb-pad/raw/raw-config-res.h b/pcsx2/USB/usb-pad/raw/raw-config-res.h deleted file mode 100644 index 608477077c..0000000000 --- a/pcsx2/USB/usb-pad/raw/raw-config-res.h +++ /dev/null @@ -1,51 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by raw-config.rc -// -#define IDD_RAWCONFIG 201 -#define IDC_STATIC -1 -#define IDC_LOGGING 1007 -#define IDC_COMBO1 1008 -#define IDC_COMBO2 1009 -#define IDC_LIST1 1010 -#define IDC_COMBO_FFB 1011 -#define IDC_BUTTON1 1012 -#define IDC_BUTTON2 1013 -#define IDC_BUTTON3 1014 -#define IDC_BUTTON4 1015 -#define IDC_BUTTON5 1016 -#define IDC_BUTTON6 1017 -#define IDC_BUTTON7 1018 -#define IDC_BUTTON8 1019 -#define IDC_BUTTON9 1020 -#define IDC_BUTTON10 1021 -#define IDC_BUTTON11 1022 -#define IDC_BUTTON12 1023 -#define IDC_BUTTON13 1024 -#define IDC_BUTTON14 1025 -#define IDC_BUTTON15 1026 -#define IDC_BUTTON16 1027 -#define IDC_BUTTON17 1028 -#define IDC_BUTTON18 1029 -#define IDC_BUTTON19 1030 -#define IDC_BUTTON20 1031 -#define IDC_BUTTON21 1032 -#define IDC_DFP_PASS 1033 -#define IDC_UNBIND 1034 -#define IDC_STATIC_CAP 1035 -#define IDC_COMBO3 1036 -#define IDC_BUTTON22 1037 -#define IDC_BUILD_DATE 1038 -#define IDC_COMBO_WHEEL_TYPE 1039 -#define IDC_TAB1 1040 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1039 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/pcsx2/USB/usb-pad/raw/raw-config.cpp b/pcsx2/USB/usb-pad/raw/raw-config.cpp deleted file mode 100644 index b5c3be7426..0000000000 --- a/pcsx2/USB/usb-pad/raw/raw-config.cpp +++ /dev/null @@ -1,925 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" - -#if !defined(_WIN32_WINNT) -#define _WIN32_WINNT 0x0502 -#endif -#include -#include -#include -#include -#include - -#include -#include -#include "USB/configuration.h" -#include "usb-pad-raw.h" -#include "raw-config-res.h" -#include - -extern HINSTANCE hInst; -#define MSG_PRESS_ESC(wnd) SendDlgItemMessageW(wnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)L"Capturing, press ESC to cancel") - -namespace usb_pad -{ - namespace raw - { - - inline bool MapExists(const MapVector& maps, const std::wstring& hid) - { - for (auto& it : maps) - if (!it.hidPath.compare(hid)) - return true; - return false; - } - - void LoadMappings(const char* dev_type, MapVector& maps) - { - maps.clear(); - - WCHAR bind[32] = {0}; - for (int j = 0; j < 25; j++) - { - std::wstring hid, tmp; - //swprintf_s(sec, TEXT("%S RAW DEVICE %d"), dev_type, j++); - - if (LoadSetting(dev_type, j, "RAW DEVICE", TEXT("HID"), hid) && !hid.empty() && !MapExists(maps, hid)) - { - Mappings m; - ZeroMemory(&m, sizeof(Mappings)); - maps.push_back(m); - Mappings& ptr = maps.back(); - - ptr.hidPath = hid; - ptr.devName = hid; - //pad_reset_data(&ptr.data[0]); - //pad_reset_data(&ptr.data[1]); - memset(&ptr.data[0], 0xFF, sizeof(wheel_data_t)); - memset(&ptr.data[1], 0xFF, sizeof(wheel_data_t)); - ptr.data[0].buttons = 0; - ptr.data[1].buttons = 0; - ptr.data[0].hatswitch = 0x8; //memset to 0xFF already or set to -1 - ptr.data[1].hatswitch = 0x8; - - for (int i = 0; i < MAX_BUTTONS; i++) - { - swprintf_s(bind, L"Button %d", i); - if (LoadSetting(dev_type, j, "RAW DEVICE", bind, tmp)) - swscanf_s(tmp.c_str(), L"%08X", &(ptr.btnMap[i])); - } - - for (int i = 0; i < MAX_AXES; i++) - { - swprintf_s(bind, L"Axis %d", i); - if (LoadSetting(dev_type, j, "RAW DEVICE", bind, tmp)) - swscanf_s(tmp.c_str(), L"%08X", &(ptr.axisMap[i])); - } - - for (int i = 0; i < 4 /*PAD_HAT_COUNT*/; i++) - { - swprintf_s(bind, L"Hat %d", i); - if (LoadSetting(dev_type, j, "RAW DEVICE", bind, tmp)) - swscanf_s(tmp.c_str(), L"%08X", &(ptr.hatMap[i])); - } - } - } - return; - } - - void SaveMappings(const char* dev_type, MapVector& maps) - { - uint32_t numDevice = 0; - for (auto& it : maps) - { - WCHAR dev[1024] = {0}, tmp[16] = {0}, bind[32] = {0}; - - SaveSetting(dev_type, numDevice, "RAW DEVICE", TEXT("HID"), it.hidPath); - - //writing everything separately, then string lengths are more predictable - for (int i = 0; i < MAX_BUTTONS; i++) - { - swprintf_s(bind, L"Button %d", i); - swprintf_s(tmp, L"%08X", it.btnMap[i]); - SaveSetting(dev_type, numDevice, "RAW DEVICE", bind, tmp); - } - - for (int i = 0; i < MAX_AXES; i++) - { - swprintf_s(bind, L"Axis %d", i); - swprintf_s(tmp, L"%08X", it.axisMap[i]); - SaveSetting(dev_type, numDevice, "RAW DEVICE", bind, tmp); - } - - for (int i = 0; i < 4 /*PAD_HAT_COUNT*/; i++) - { - swprintf_s(bind, L"Hat %d", i); - swprintf_s(tmp, L"%08X", it.hatMap[i]); - SaveSetting(dev_type, numDevice, "RAW DEVICE", bind, tmp); - } - numDevice++; - } - - return; - } - -/// Dialogs -#define TXT(x) (#x) - const char* BTN2TXT[] = { - "Cross", - "Square", - "Circle", - "Triangle", - "R1", - "L1", - "R2", - "L2", - "Select", - "Start", - "R3", - "L3"}; - - const char* AXIS2TXT[] = { - "Axis X", - "Axis Y", - "Axis Z", - //"Axis RX", - //"Axis RY", - "Axis RZ", - "Hat Switch"}; - - void resetState(HWND hW); - HWND dgHwnd = NULL; - //std::vector joysName; - static std::vector joysDev; - static DWORD selectedJoy[2]; - //std::vector::iterator* tmpIter; - - typedef struct _DevInfo - { - int ply; - RID_DEVICE_INFO_HID hid; - - bool operator==(const _DevInfo& t) const - { - if (ply == t.ply && hid.dwProductId == t.hid.dwProductId && - hid.dwVendorId == t.hid.dwVendorId && - hid.dwVersionNumber == t.hid.dwVersionNumber && - hid.usUsage == t.hid.usUsage && - hid.usUsagePage == t.hid.usUsagePage) - return true; - return false; - } - - bool operator<(const _DevInfo& t) const - { - if (ply < t.ply) - return true; - if (hid.dwProductId < t.hid.dwProductId) - return true; - if (hid.dwVendorId < t.hid.dwVendorId) - return true; - if (hid.dwVersionNumber < t.hid.dwVersionNumber) - return true; - return false; - } - - } DevInfo_t; - - //typedef std::map MappingsMap; - //MappingsMap mappings; - - uint32_t axisDiff[MAX_AXES]; //previous axes values - bool axisPass2 = false; - - //eh, global var for currently selected player - static int plyCapturing = 0; - PS2Buttons btnCapturing = PAD_BUTTON_COUNT; - PS2Axis axisCapturing = PAD_AXIS_COUNT; - PS2HatSwitch hatCapturing = PAD_HAT_COUNT; - - void populate(HWND hW, RawDlgConfig* cfg) - { - //mappings.clear(); - //joysName.clear(); - //joysName.push_back("None"); - joysDev.clear(); - joysDev.push_back(L""); - - int i = 0, sel_idx = 1; - HANDLE usbHandle = INVALID_HANDLE_VALUE; - DWORD needed = 0; - HDEVINFO devInfo; - GUID guid; - SP_DEVICE_INTERFACE_DATA diData; - PSP_DEVICE_INTERFACE_DETAIL_DATA didData = NULL; - HIDD_ATTRIBUTES attr; - PHIDP_PREPARSED_DATA pPreparsedData = NULL; - HIDP_CAPS caps; - OVERLAPPED ovl; - - memset(&ovl, 0, sizeof(OVERLAPPED)); - ovl.hEvent = CreateEvent(0, 0, 0, 0); - ovl.Offset = 0; - ovl.OffsetHigh = 0; - - HidD_GetHidGuid(&guid); - - devInfo = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_DEVICEINTERFACE); - if (!devInfo) - return; - - diData.cbSize = sizeof(diData); - - //Mappings listview - LVCOLUMN LvCol; - memset(&LvCol, 0, sizeof(LvCol)); - LvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - LvCol.pszText = TEXT("Device"); - LvCol.cx = 0x4F; - ListView_InsertColumn(GetDlgItem(hW, IDC_LIST1), 0, &LvCol); - - LvCol.pszText = TEXT("PC"); - ListView_InsertColumn(GetDlgItem(hW, IDC_LIST1), 1, &LvCol); - - LvCol.pszText = TEXT("PS2"); - ListView_InsertColumn(GetDlgItem(hW, IDC_LIST1), 2, &LvCol); - - //Tab control - TCITEM tie; - tie.pszText = TEXT("Player 1"); - tie.cchTextMax = 32; - tie.mask = TCIF_TEXT; - SendDlgItemMessage(hW, IDC_TAB1, TCM_INSERTITEM, 0, (LPARAM)&tie); - - tie.pszText = TEXT("Player 2"); - SendDlgItemMessage(hW, IDC_TAB1, TCM_INSERTITEM, 1, (LPARAM)&tie); - - //Selected FFB target device - SendDlgItemMessageA(hW, IDC_COMBO_FFB, CB_ADDSTRING, 0, (LPARAM) "None"); - SendDlgItemMessage(hW, IDC_COMBO_FFB, CB_SETCURSEL, 0, 0); - - while (SetupDiEnumDeviceInterfaces(devInfo, 0, &guid, i, &diData)) - { - if (usbHandle != INVALID_HANDLE_VALUE) - CloseHandle(usbHandle); - - SetupDiGetDeviceInterfaceDetail(devInfo, &diData, 0, 0, &needed, 0); - - didData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(needed); - if (!didData) - break; - didData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if (!SetupDiGetDeviceInterfaceDetail(devInfo, &diData, didData, needed, 0, 0)) - { - free(didData); - break; - } - - usbHandle = CreateFile(didData->DevicePath, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - - if (usbHandle == INVALID_HANDLE_VALUE) - { - Console.Warning("Could not open device %i", i); - free(didData); - i++; - continue; - } - - HidD_GetAttributes(usbHandle, &attr); - if (!HidD_GetPreparsedData(usbHandle, &pPreparsedData)) - { - Console.Warning("Could not get preparsed data from %04x:%04x", attr.VendorID, attr.ProductID); - free(didData); - i++; - continue; - } - - HidP_GetCaps(pPreparsedData, &caps); - - if (caps.UsagePage == HID_USAGE_PAGE_GENERIC && - (caps.Usage == HID_USAGE_GENERIC_JOYSTICK || caps.Usage == HID_USAGE_GENERIC_GAMEPAD)) - { - std::wstring strPath(didData->DevicePath); - std::transform(strPath.begin(), strPath.end(), strPath.begin(), ::toupper); - joysDev.push_back(strPath); - - wchar_t str[MAX_PATH + 1]; - if (HidD_GetProductString(usbHandle, str, sizeof(str))) - SendDlgItemMessageW(hW, IDC_COMBO_FFB, CB_ADDSTRING, 0, (LPARAM)str); - else - { - swprintf_s(str, L"%04X:%04X", attr.VendorID, attr.ProductID); - SendDlgItemMessageW(hW, IDC_COMBO_FFB, CB_ADDSTRING, 0, (LPARAM)str); - } - - if (cfg->player_joys[0] == strPath) - { - SendDlgItemMessage(hW, IDC_COMBO_FFB, CB_SETCURSEL, sel_idx, 0); - selectedJoy[0] = sel_idx; - } - else if (cfg->player_joys[1] == strPath) - { - selectedJoy[1] = sel_idx; - } - sel_idx++; - } - free(didData); - HidD_FreePreparsedData(pPreparsedData); - i++; - } - if (usbHandle != INVALID_HANDLE_VALUE) - CloseHandle(usbHandle); - } - - void populateMappings(HWND hW) - { - LVITEM lvItem; - HWND lv = GetDlgItem(hW, IDC_LIST1); - - //LoadMappings(mapVector); - - memset(&lvItem, 0, sizeof(lvItem)); - - lvItem.mask = LVIF_TEXT | LVIF_PARAM; - lvItem.cchTextMax = 256; - lvItem.iItem = 0; - lvItem.iSubItem = 0; - - TCHAR tmp[256]; - int m[3]; - - for (auto& it : mapVector) - { - //TODO feels a bit hacky - bool isKB = (it.devName == TEXT("Keyboard")); - if (isKB) - { - m[0] = PAD_BUTTON_COUNT; - m[1] = PAD_AXIS_COUNT; - m[2] = 4; - } - else - { - m[0] = MAX_BUTTONS; - m[1] = MAX_AXES; - m[2] = 4; - } - - for (int i = 0; i < m[0]; i++) - { - //if((*it).btnMap[i] >= PAD_BUTTON_COUNT) - // continue; - int btn = it.btnMap[i]; - int val = PLY_GET_VALUE(plyCapturing, btn); - - lvItem.iItem = ListView_GetItemCount(lv); - if (PLY_IS_MAPPED(plyCapturing, btn) /*&& val < PAD_BUTTON_COUNT*/) - { - swprintf_s(tmp, 255, L"%s", it.devName.c_str()); //TODO - lvItem.pszText = tmp; - lvItem.lParam = (LPARAM) & (it.btnMap[i]); - ListView_InsertItem(lv, &lvItem); - swprintf_s(tmp, 255, L"P%d: Button %d", plyCapturing + 1, isKB ? val : i); - ListView_SetItemText(lv, lvItem.iItem, 1, tmp); - - swprintf_s(tmp, 255, L"%S", isKB ? BTN2TXT[i] : BTN2TXT[val]); - ListView_SetItemText(lv, lvItem.iItem, 2, tmp); - } - } - - for (int i = 0; i < m[1]; i++) - { - //if(it.axisMap[i] >= PAD_AXIS_COUNT) - // continue; - int axis = it.axisMap[i]; - int val = PLY_GET_VALUE(plyCapturing, axis); - - if (PLY_IS_MAPPED(plyCapturing, axis) /* && val < PAD_AXIS_COUNT*/) - { - lvItem.iItem = ListView_GetItemCount(lv); - //swprintf_s(tmp, 255, L"%s", it.devName.c_str()); //TODO - lvItem.pszText = (LPWSTR)it.devName.c_str(); - lvItem.lParam = (LPARAM) & (it.axisMap[i]); - ListView_InsertItem(lv, &lvItem); - - swprintf_s(tmp, 255, L"P%d: Axis %d", plyCapturing + 1, isKB ? val : i); - ListView_SetItemText(lv, lvItem.iItem, 1, tmp); - - swprintf_s(tmp, 255, L"%S", isKB ? AXIS2TXT[i] : AXIS2TXT[val]); - ListView_SetItemText(lv, lvItem.iItem, 2, tmp); - } - } - - for (int i = 0; i < m[2]; i++) - { - int hat = it.hatMap[i]; - int val = PLY_GET_VALUE(plyCapturing, hat); - - if (PLY_IS_MAPPED(plyCapturing, hat) /*&& val < PAD_HAT_COUNT*/) - { - lvItem.iItem = ListView_GetItemCount(lv); - lvItem.pszText = (LPWSTR)it.devName.c_str(); - lvItem.lParam = (LPARAM) & (it.hatMap[i]); - ListView_InsertItem(lv, &lvItem); - - swprintf_s(tmp, 255, L"P%d: Hat %d", plyCapturing + 1, isKB ? val : i); - ListView_SetItemText(lv, lvItem.iItem, 1, tmp); - - swprintf_s(tmp, 255, L"Hat %d", isKB ? i : val); - ListView_SetItemText(lv, lvItem.iItem, 2, tmp); - } - } - } - } - - static void ParseRawInput(PRAWINPUT pRawInput, HWND hW) - { - PHIDP_PREPARSED_DATA pPreparsedData = NULL; - HIDP_CAPS Caps; - PHIDP_BUTTON_CAPS pButtonCaps = NULL; - PHIDP_VALUE_CAPS pValueCaps = NULL; - USHORT capsLength; - UINT bufferSize; - USAGE usage[MAX_BUTTONS]; - ULONG i, usageLength, value; - TCHAR name[1024] = {0}; - UINT nameSize = 1024; - UINT pSize; - RID_DEVICE_INFO devInfo; - std::wstring devName; - //DevInfo_t mapDevInfo; - Mappings* mapping = NULL; - int axis; - TCHAR buf[256]; - //std::pair iter; - - // - // Get the preparsed data block - // - GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, name, &nameSize); - pSize = sizeof(devInfo); - GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &devInfo, &pSize); - - if (devInfo.dwType == RIM_TYPEKEYBOARD) - { - devName = TEXT("Keyboard"); - } - else - { - CHECK(GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0); - CHECK(pPreparsedData = (PHIDP_PREPARSED_DATA)malloc(bufferSize)); - CHECK((int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0); - CHECK(HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS); - - devName = name; - std::transform(devName.begin(), devName.end(), devName.begin(), ::toupper); - } - - for (auto& it : mapVector) - { - if (it.hidPath == devName) - { - mapping = &(it); - break; - } - } - - if (mapping == NULL) - { - Mappings m; // = new Mappings; - ZeroMemory(&m, sizeof(Mappings)); - mapVector.push_back(m); - mapping = &mapVector.back(); - mapping->devName = devName; - mapping->hidPath = devName; - } - //TODO get real dev name, probably from registry (see PAD Windows) - if (!mapping->devName.length()) - mapping->devName = devName; - - if (devInfo.dwType == RIM_TYPEKEYBOARD && - (pRawInput->data.keyboard.Flags & RI_KEY_BREAK) != RI_KEY_BREAK) - { - if (pRawInput->data.keyboard.VKey == 0xff) - return; //TODO - if (pRawInput->data.keyboard.VKey == VK_ESCAPE) - { - resetState(hW); - return; - } - if (btnCapturing < PAD_BUTTON_COUNT) - { - mapping->btnMap[btnCapturing] = PLY_SET_MAPPED(plyCapturing, pRawInput->data.keyboard.VKey); - swprintf_s(buf, TEXT("Captured KB button %d"), pRawInput->data.keyboard.VKey); - SendDlgItemMessage(dgHwnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf); - btnCapturing = PAD_BUTTON_COUNT; - } - else if (hatCapturing < PAD_HAT_COUNT) - { - for (int h = 0; h < 4; h++) - { - if (HATS_8TO4[h] == hatCapturing) - mapping->hatMap[h] = PLY_SET_MAPPED(plyCapturing, pRawInput->data.keyboard.VKey); - } - swprintf_s(buf, TEXT("Captured KB button %d"), pRawInput->data.keyboard.VKey); - SendDlgItemMessage(dgHwnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf); - hatCapturing = PAD_HAT_COUNT; - } - else if (axisCapturing < PAD_AXIS_COUNT) - { - mapping->axisMap[axisCapturing] = PLY_SET_MAPPED(plyCapturing, pRawInput->data.keyboard.VKey); - swprintf_s(buf, TEXT("Captured KB button %d"), pRawInput->data.keyboard.VKey); - SendDlgItemMessage(dgHwnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf); - axisCapturing = PAD_AXIS_COUNT; - } - } - else //if(devInfo.dwType == RIM_TYPEHID) - { - //Capture buttons - if (btnCapturing < PAD_BUTTON_COUNT || hatCapturing < PAD_HAT_COUNT) - { - // Button caps - CHECK(pButtonCaps = (PHIDP_BUTTON_CAPS)malloc(sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps)); - - capsLength = Caps.NumberInputButtonCaps; - CHECK(HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS); - int numberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1; - - usageLength = numberOfButtons; - CHECK( - HidP_GetUsages( - HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData, - (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS); - - if (usageLength > 0) //Using first button only though - { - if (btnCapturing < PAD_BUTTON_COUNT) - { - mapping->btnMap[usage[0] - pButtonCaps->Range.UsageMin] = PLY_SET_MAPPED(plyCapturing, btnCapturing); - btnCapturing = PAD_BUTTON_COUNT; - } - else if (hatCapturing < PAD_HAT_COUNT) - { - mapping->hatMap[usage[0] - pButtonCaps->Range.UsageMin] = PLY_SET_MAPPED(plyCapturing, hatCapturing); - hatCapturing = PAD_HAT_COUNT; - } - } - } - else if (axisCapturing < PAD_AXIS_COUNT) - { - // Value caps - CHECK(pValueCaps = (PHIDP_VALUE_CAPS)malloc(sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps)); - capsLength = Caps.NumberInputValueCaps; - CHECK(HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS); - - for (i = 0; i < Caps.NumberInputValueCaps && axisCapturing < PAD_AXIS_COUNT; i++) - { - CHECK( - HidP_GetUsageValue( - HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData, - (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS); - - uint32_t logical = pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin; - - switch (pValueCaps[i].Range.UsageMin) - { - case HID_USAGE_GENERIC_X: - case HID_USAGE_GENERIC_Y: - case HID_USAGE_GENERIC_Z: - case HID_USAGE_GENERIC_RX: - case HID_USAGE_GENERIC_RY: - case HID_USAGE_GENERIC_RZ: - axis = pValueCaps[i].Range.UsageMin - HID_USAGE_GENERIC_X; - if (axisPass2) - { - if ((uint32_t)abs((int)(axisDiff[axis] - value)) > (logical >> 2)) - { - mapping->axisMap[axis] = PLY_SET_MAPPED(plyCapturing, axisCapturing); - axisPass2 = false; - swprintf_s(buf, TEXT("Captured wheel axis %d"), axis); - SendDlgItemMessage(dgHwnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf); - axisCapturing = PAD_AXIS_COUNT; - goto Error; - } - break; - } - axisDiff[axis] = value; - break; - - case 0x39: // Hat Switch - if (value < 0x8) - { - mapping->axisMap[6] = PLY_SET_MAPPED(plyCapturing, axisCapturing); - axisPass2 = false; - swprintf_s(buf, TEXT("Captured wheel hat switch")); - SendDlgItemMessage(dgHwnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf); - axisCapturing = PAD_AXIS_COUNT; - goto Error; - } - break; - } - } - - axisPass2 = true; - } - } - Error: - SAFE_FREE(pPreparsedData); - SAFE_FREE(pButtonCaps); - SAFE_FREE(pValueCaps); - } - - //Also when switching player - void resetState(HWND hW) - { - SendDlgItemMessage(hW, IDC_COMBO_FFB, CB_SETCURSEL, selectedJoy[plyCapturing], 0); - SendDlgItemMessage(hW, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)TEXT("")); - - btnCapturing = PAD_BUTTON_COUNT; - axisCapturing = PAD_AXIS_COUNT; - hatCapturing = PAD_HAT_COUNT; - ListView_DeleteAllItems(GetDlgItem(hW, IDC_LIST1)); - populateMappings(hW); - } - - static void Register(HWND hW) - { - RAWINPUTDEVICE rid[3]; - rid[0].usUsagePage = 0x01; - rid[0].usUsage = 0x05; - rid[0].dwFlags = hW ? RIDEV_INPUTSINK : RIDEV_REMOVE; // adds game pad - rid[0].hwndTarget = hW; - - rid[1].usUsagePage = 0x01; - rid[1].usUsage = 0x04; - rid[1].dwFlags = hW ? RIDEV_INPUTSINK : RIDEV_REMOVE; // adds joystick - rid[1].hwndTarget = hW; - - rid[2].usUsagePage = 0x01; - rid[2].usUsage = 0x06; - rid[2].dwFlags = hW ? RIDEV_INPUTSINK /*| RIDEV_NOLEGACY*/ : RIDEV_REMOVE; // adds HID keyboard and also ignores legacy keyboard messages - rid[2].hwndTarget = hW; - - if (!RegisterRawInputDevices(rid, 3, sizeof(rid[0]))) - { - SendDlgItemMessage(hW, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)TEXT("Could not register raw input devices.")); - } - } - - INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - - TCHAR buf[256]; - LVITEM lv; - RawDlgConfig* cfg = (RawDlgConfig*)GetWindowLongPtr(hW, GWLP_USERDATA); - int ret = 0; - switch (uMsg) - { - case WM_INITDIALOG: - if (!InitHid()) - return FALSE; - dgHwnd = hW; - SetWindowLongPtr(hW, GWLP_USERDATA, lParam); - //SendDlgItemMessage(hW, IDC_BUILD_DATE, WM_SETTEXT, 0, (LPARAM)__DATE__ " " __TIME__); - ListView_SetExtendedListViewStyle(GetDlgItem(hW, IDC_LIST1), LVS_EX_FULLROWSELECT); - - //LoadConfig(); - cfg = (RawDlgConfig*)lParam; - - if (!LoadSetting(cfg->dev_type, PLAYER_ONE_PORT, APINAME, N_JOYSTICK, cfg->player_joys[0])) - cfg->player_joys[0].clear(); - - if (!LoadSetting(cfg->dev_type, PLAYER_TWO_PORT, APINAME, N_JOYSTICK, cfg->player_joys[1])) - cfg->player_joys[1].clear(); - - LoadSetting(cfg->dev_type, PLAYER_ONE_PORT, APINAME, N_WHEEL_PT, cfg->pt[0]); - LoadSetting(cfg->dev_type, PLAYER_TWO_PORT, APINAME, N_WHEEL_PT, cfg->pt[1]); - - Register(hW); - LoadMappings(cfg->dev_type, mapVector); - //if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); - CheckDlgButton(hW, IDC_DFP_PASS, cfg->pt[0]); - populate(hW, cfg); - resetState(hW); - return TRUE; - - case WM_INPUT: - ret = S_FALSE; - if (axisCapturing != PAD_AXIS_COUNT || - btnCapturing != PAD_BUTTON_COUNT || - hatCapturing != PAD_HAT_COUNT) - { - ret = 0; - PRAWINPUT pRawInput; - UINT bufferSize; - UINT cbsize = sizeof(RAWINPUT); - GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER)); - pRawInput = (PRAWINPUT)malloc(bufferSize); - if (!pRawInput) - break; - if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER)) > 0) - ParseRawInput(pRawInput, hW); - free(pRawInput); - - if (axisCapturing == PAD_AXIS_COUNT && - btnCapturing == PAD_BUTTON_COUNT && - hatCapturing == PAD_HAT_COUNT) - { - resetState(hW); - } - } - DefWindowProc(hW, uMsg, wParam, lParam); //TODO should call for cleanup? - return ret; - - case WM_KEYDOWN: - if (LOWORD(lParam) == VK_ESCAPE) - { - resetState(hW); - return TRUE; - } - break; - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) - { - case TCN_SELCHANGE: - switch (LOWORD(wParam)) - { - case IDC_TAB1: - plyCapturing = SendDlgItemMessage(hW, IDC_TAB1, TCM_GETCURSEL, 0, 0); - CheckDlgButton(hW, IDC_DFP_PASS, cfg->pt[plyCapturing]); - resetState(hW); - break; - } - break; - } - break; - case WM_TIMER: - if (wParam == 1) - resetState(hW); - break; - case WM_COMMAND: - switch (HIWORD(wParam)) - { - case LBN_SELCHANGE: - switch (LOWORD(wParam)) - { - case IDC_COMBO_FFB: - selectedJoy[plyCapturing] = SendDlgItemMessage(hW, IDC_COMBO_FFB, CB_GETCURSEL, 0, 0); - //player_joys[plyCapturing] = *(joysDev.begin() + selectedJoy[plyCapturing]); - //resetState(hW); - /*if(selectedJoy[plyCapturing] > 0 && selectedJoy[plyCapturing] == selectedJoy[1-plyCapturing]) - { - selectedJoy[plyCapturing] = 0; - resetState(hW); - SendDlgItemMessage(hW, IDC_COMBO_FFB, CB_SETCURSEL, selectedJoy[plyCapturing], 0); - //But would you want to? - SendDlgItemMessageA(hW, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)"Both players can't have the same controller."); //Actually, whatever, but config logics are limited ;P - }*/ - break; - case IDC_COMBO1: - break; - case IDC_COMBO2: - break; - default: - return FALSE; - } - break; - case BN_CLICKED: - if (axisCapturing == PAD_AXIS_COUNT && - btnCapturing == PAD_BUTTON_COUNT && - LOWORD(wParam) >= IDC_BUTTON13 && - LOWORD(wParam) <= IDC_BUTTON16) - { - switch (LOWORD(wParam)) - { - case IDC_BUTTON13: - hatCapturing = PAD_HAT_N; - break; - case IDC_BUTTON14: - hatCapturing = PAD_HAT_W; - break; - case IDC_BUTTON15: - hatCapturing = PAD_HAT_E; - break; - case IDC_BUTTON16: - hatCapturing = PAD_HAT_S; - break; - } - MSG_PRESS_ESC(hW); - SetTimer(hW, 1, 5000, nullptr); - } - - switch (LOWORD(wParam)) - { - case IDC_DFP_PASS: - cfg->pt[plyCapturing] = IsDlgButtonChecked(hW, IDC_DFP_PASS) > 0; - break; - case IDC_UNBIND: - HWND lhW; - lhW = GetDlgItem(hW, IDC_LIST1); - while (1) - { - ZeroMemory(&lv, sizeof(LVITEM)); - int sel = ListView_GetNextItem(lhW, -1, LVNI_SELECTED); - if (sel < 0) - break; - lv.iItem = sel; - lv.mask = LVIF_PARAM; - ListView_GetItem(lhW, &lv); - ListView_DeleteItem(lhW, sel); - ListView_EnsureVisible(lhW, sel, 0); - - int* map = (int*)lv.lParam; - if (map) - *map = PLY_UNSET_MAPPED(plyCapturing, *map); - } - resetState(hW); - break; - case IDC_BUTTON1: //cross - case IDC_BUTTON2: //square - case IDC_BUTTON3: //circle - case IDC_BUTTON4: //triangle - case IDC_BUTTON5: //L1 - case IDC_BUTTON6: //R1 - case IDC_BUTTON7: //L2 - case IDC_BUTTON8: //R2 - case IDC_BUTTON9: //select - case IDC_BUTTON10: //start - case IDC_BUTTON11: //L3 - case IDC_BUTTON12: //R3 - if (axisCapturing == PAD_AXIS_COUNT && - hatCapturing == PAD_HAT_COUNT) - { - btnCapturing = (PS2Buttons)(LOWORD(wParam) - IDC_BUTTON1); - MSG_PRESS_ESC(hW); - SetTimer(hW, 1, 5000, nullptr); - } - return TRUE; - case IDC_BUTTON17: //x - case IDC_BUTTON18: //y - case IDC_BUTTON19: //z - case IDC_BUTTON20: //rz - case IDC_BUTTON21: //hat - if (btnCapturing == PAD_BUTTON_COUNT && - hatCapturing == PAD_HAT_COUNT) - { - axisCapturing = (PS2Axis)(LOWORD(wParam) - IDC_BUTTON17); - swprintf_s(buf, TEXT("Capturing for axis %u, press ESC to cancel"), axisCapturing); - SendDlgItemMessage(hW, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf); - SetTimer(hW, 1, 5000, nullptr); - } - return TRUE; - case IDCANCEL: - if (btnCapturing < PAD_BUTTON_COUNT || - axisCapturing < PAD_AXIS_COUNT || - hatCapturing < PAD_HAT_COUNT) - return FALSE; - Register(nullptr); - EndDialog(hW, FALSE); - return TRUE; - case IDOK: - Register(nullptr); - cfg = (RawDlgConfig*)GetWindowLongPtr(hW, GWLP_USERDATA); - cfg->player_joys[0] = joysDev[selectedJoy[0]]; - cfg->player_joys[1] = joysDev[selectedJoy[1]]; - - INT_PTR res = RESULT_OK; - - if (!SaveSetting(cfg->dev_type, PLAYER_ONE_PORT, APINAME, N_JOYSTICK, cfg->player_joys[0])) - res = RESULT_FAILED; - if (!SaveSetting(cfg->dev_type, PLAYER_TWO_PORT, APINAME, N_JOYSTICK, cfg->player_joys[1])) - res = RESULT_FAILED; - - SaveMappings(cfg->dev_type, mapVector); - - if (!SaveSetting(cfg->dev_type, PLAYER_ONE_PORT, APINAME, N_WHEEL_PT, cfg->pt[0])) - res = RESULT_FAILED; - if (!SaveSetting(cfg->dev_type, PLAYER_TWO_PORT, APINAME, N_WHEEL_PT, cfg->pt[1])) - res = RESULT_FAILED; - - EndDialog(hW, res); - return TRUE; - } - } - } - - return S_OK; //DefWindowProc(hW, uMsg, wParam, lParam); - } - - } // namespace raw -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/raw/raw-config.rc b/pcsx2/USB/usb-pad/raw/raw-config.rc deleted file mode 100644 index 173f9cc239..0000000000 --- a/pcsx2/USB/usb-pad/raw/raw-config.rc +++ /dev/null @@ -1,146 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "raw-config-res.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winresrc.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_RAWCONFIG DIALOGEX 0, 0, 385, 272 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Configure (raw input api)" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "OK",IDOK,270,252,50,14 - PUSHBUTTON "Cancel",IDCANCEL,326,252,50,14 - CONTROL "",IDC_TAB1,"SysTabControl32",0x0,6,6,372,240 - PUSHBUTTON "Cross / A",IDC_BUTTON1,192,42,50,14 - PUSHBUTTON "Square / X",IDC_BUTTON2,246,42,50,14 - PUSHBUTTON "Circle / B",IDC_BUTTON3,192,60,50,14 - PUSHBUTTON "Triangle / Y",IDC_BUTTON4,246,60,50,14 - PUSHBUTTON "L1 / L",IDC_BUTTON6,192,79,50,14 - PUSHBUTTON "R1 / R",IDC_BUTTON5,246,79,50,14 - PUSHBUTTON "L2",IDC_BUTTON8,192,96,50,14 - PUSHBUTTON "R2",IDC_BUTTON7,246,96,50,14 - PUSHBUTTON "L3",IDC_BUTTON12,192,114,50,14 - PUSHBUTTON "R3",IDC_BUTTON11,246,114,50,14 - PUSHBUTTON "Select",IDC_BUTTON9,192,132,50,14 - PUSHBUTTON "Start",IDC_BUTTON10,246,132,50,14 - PUSHBUTTON "Up",IDC_BUTTON13,224,161,50,14 - PUSHBUTTON "Left",IDC_BUTTON14,194,179,50,14 - PUSHBUTTON "Right",IDC_BUTTON15,254,179,50,14 - PUSHBUTTON "Down",IDC_BUTTON16,224,196,50,14 - PUSHBUTTON "Wheel",IDC_BUTTON17,306,42,50,14 - PUSHBUTTON "Clutch",IDC_BUTTON18,306,60,50,14 - PUSHBUTTON "Throttle",IDC_BUTTON19,306,79,50,14 - PUSHBUTTON "Brake",IDC_BUTTON20,306,95,50,14 - PUSHBUTTON "Hatswitch",IDC_BUTTON21,306,114,50,14 - LTEXT "",IDC_STATIC_CAP,6,252,156,8 - CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,12,42,174,136 - PUSHBUTTON "Unbind",IDC_UNBIND,12,180,50,14 - COMBOBOX IDC_COMBO_FFB,18,207,167,51,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Logitech wheel pass-through",IDC_DFP_PASS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,224,168,12,WS_EX_STATICEDGE - GROUPBOX "Bind axes",IDC_STATIC,301,30,59,102 - GROUPBOX "Bind hat switch to a button",IDC_STATIC,192,150,114,66 - GROUPBOX "FF / pass-through device",IDC_STATIC,14,196,175,43 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_RAWCONFIG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 378 - TOPMARGIN, 7 - BOTTOMMARGIN, 265 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_RAWCONFIG AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Spanish (Argentina) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) -LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "raw-config-res.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""WinResrc.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Spanish (Argentina) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/pcsx2/USB/usb-pad/raw/usb-pad-raw.cpp b/pcsx2/USB/usb-pad/raw/usb-pad-raw.cpp deleted file mode 100644 index d8cef35aec..0000000000 --- a/pcsx2/USB/usb-pad/raw/usb-pad-raw.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "USB/USB.h" -#include "USB/Win32/Config_usb.h" -#include "usb-pad-raw.h" - -namespace usb_pad -{ - namespace raw - { - - void RawInputPad::WriterThread(void* ptr) - { - DWORD written = 0; - std::array buf; - - RawInputPad* pad = static_cast(ptr); - pad->mWriterThreadIsRunning = true; - - while (pad->mUsbHandle != INVALID_HANDLE_VALUE) - { - if (pad->mFFData.wait_dequeue_timed(buf, std::chrono::milliseconds(1000))) - { - const DWORD res = WriteFile(pad->mUsbHandle, buf.data(), buf.size(), &written, &pad->mOLWrite); - uint8_t* d = buf.data(); - - WaitForSingleObject(pad->mOLWrite.hEvent, 1000); - } - } - - pad->mWriterThreadIsRunning = false; - } - - void RawInputPad::ReaderThread(void* ptr) - { - RawInputPad* pad = static_cast(ptr); - DWORD read = 0; - std::array report; //32 is random - - pad->mReaderThreadIsRunning = true; - int errCount = 0; - - while (pad->mUsbHandle != INVALID_HANDLE_VALUE) - { - if (GetOverlappedResult(pad->mUsbHandle, &pad->mOLRead, &read, FALSE)) // TODO check if previous read finally completed after WaitForSingleObject timed out - ReadFile(pad->mUsbHandle, report.data(), std::min(pad->mCaps.InputReportByteLength, (USHORT)report.size()), nullptr, &pad->mOLRead); // Seems to only read data when input changes and not current state overall - - if (WaitForSingleObject(pad->mOLRead.hEvent, 1000) == WAIT_OBJECT_0) - { - if (!pad->mReportData.try_enqueue(report)) // TODO May leave queue with too stale data. Use multi-producer/consumer queue? - { - if (!errCount) - Console.Warning("%s: Could not enqueue report data: %zd\n", APINAME, pad->mReportData.size_approx()); - errCount = (++errCount) % 16; - } - } - } - - pad->mReaderThreadIsRunning = false; - } - - int RawInputPad::TokenIn(uint8_t* buf, int len) - { - const int player = 1 - mPort; - - //Console.Warning("usb-pad: poll len=%li\n", len); - if (mDoPassthrough) - { - std::array report; //32 is random - if (mReportData.try_dequeue(report)) - { - //ZeroMemory(buf, len); - int size = std::min((int)mCaps.InputReportByteLength, len); - memcpy(buf, report.data(), size); - return size; - } - return 0; - } - - //in case compiler magic with bitfields interferes - wheel_data_t data_summed; - memset(&data_summed, 0xFF, sizeof(data_summed)); - data_summed.hatswitch = 0x8; - data_summed.buttons = 0; - - int copied = 0; - //TODO fix the logics, also Config.cpp - for (auto& it : mapVector) - { - - if (data_summed.steering < it.data[player].steering) - { - data_summed.steering = it.data[player].steering; - copied |= 1; - } - - //if(data_summed.clutch < it.data[player].clutch) - // data_summed.clutch = it.data[player].clutch; - - if (data_summed.throttle < it.data[player].throttle) - { - data_summed.throttle = it.data[player].throttle; - copied |= 2; - } - - if (data_summed.brake < it.data[player].brake) - { - data_summed.brake = it.data[player].brake; - copied |= 4; - } - - data_summed.buttons |= it.data[player].buttons; - if (data_summed.hatswitch > it.data[player].hatswitch) - data_summed.hatswitch = it.data[player].hatswitch; - } - - if (!copied) - memcpy(&data_summed, &mDataCopy, sizeof(wheel_data_t)); - else - { - if (!(copied & 1)) - data_summed.steering = mDataCopy.steering; - if (!(copied & 2)) - data_summed.throttle = mDataCopy.throttle; - if (!(copied & 4)) - data_summed.brake = mDataCopy.brake; - } - - pad_copy_data(mType, buf, data_summed); - - if (copied) - memcpy(&mDataCopy, &data_summed, sizeof(wheel_data_t)); - return len; - } - - int RawInputPad::TokenOut(const uint8_t* data, int len) - { - if (mUsbHandle == INVALID_HANDLE_VALUE) - return 0; - - if (data[0] == 0x8 || data[0] == 0xB) - return len; - //if(data[0] == 0xF8 && data[1] == 0x5) sendCrap = true; - if (data[0] == 0xF8 && - /* Allow range changes */ - !(data[1] == 0x81 || data[1] == 0x02 || data[1] == 0x03)) - return len; //don't send extended commands - - std::array report{0}; - - //If i'm reading it correctly MOMO report size for output has Report Size(8) and Report Count(7), so that's 7 bytes - //Now move that 7 bytes over by one and add report id of 0 (right?). Supposedly mandatory for HIDs. - memcpy(report.data() + 1, data, report.size() - 1); - - if (!mFFData.enqueue(report)) - { - return 0; - } - - return len; - } - - static void ParseRawInputHID(PRAWINPUT pRawInput, int subtype) - { - PHIDP_PREPARSED_DATA pPreparsedData = NULL; - HIDP_CAPS Caps; - PHIDP_BUTTON_CAPS pButtonCaps = NULL; - PHIDP_VALUE_CAPS pValueCaps = NULL; - UINT bufferSize = 0; - ULONG usageLength, value; - TCHAR name[1024] = {0}; - UINT nameSize = 1024; - RID_DEVICE_INFO devInfo = {0}; - std::wstring devName; - USHORT capsLength = 0; - USAGE usage[MAX_BUTTONS] = {0}; - Mappings* mapping = NULL; - int numberOfButtons; - - auto iter = mappings.find(pRawInput->header.hDevice); - if (iter != mappings.end()) - { - mapping = iter->second; - } - else - { - GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, name, &nameSize); - - devName = name; - std::transform(devName.begin(), devName.end(), devName.begin(), ::toupper); - - for (auto& it : mapVector) - { - if (it.hidPath == devName) - { - mapping = ⁢ - mappings[pRawInput->header.hDevice] = mapping; - break; - } - } - } - - if (mapping == NULL) - return; - - CHECK(GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0); - CHECK(pPreparsedData = (PHIDP_PREPARSED_DATA)malloc(bufferSize)); - CHECK((int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0); - CHECK(HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS); - //pSize = sizeof(devInfo); - //GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &devInfo, &pSize); - - //Unset buttons/axes mapped to this device - //pad_reset_data(&mapping->data[0]); - //pad_reset_data(&mapping->data[1]); - memset(&mapping->data[0], 0xFF, sizeof(wheel_data_t)); - memset(&mapping->data[1], 0xFF, sizeof(wheel_data_t)); - mapping->data[0].buttons = 0; - mapping->data[1].buttons = 0; - mapping->data[0].hatswitch = 0x8; - mapping->data[1].hatswitch = 0x8; - - //Get pressed buttons - CHECK(pButtonCaps = (PHIDP_BUTTON_CAPS)malloc(sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps)); - //If fails, maybe wheel only has axes - capsLength = Caps.NumberInputButtonCaps; - HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData); - - numberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1; - usageLength = countof(usage); - NTSTATUS stat; - if ((stat = HidP_GetUsages( - HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData, - (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid)) == HIDP_STATUS_SUCCESS) - { - for (uint32_t i = 0; i < usageLength; i++) - { - uint16_t btn = mapping->btnMap[usage[i] - pButtonCaps->Range.UsageMin]; - for (int j = 0; j < 2; j++) - { - PS2WheelTypes wt = (PS2WheelTypes)subtype; - if (PLY_IS_MAPPED(j, btn)) - { - uint32_t wtbtn = 1 << convert_wt_btn(wt, PLY_GET_VALUE(j, btn)); - mapping->data[j].buttons |= wtbtn; - } - } - } - } - - /// Get axes' values - CHECK(pValueCaps = (PHIDP_VALUE_CAPS)malloc(sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps)); - capsLength = Caps.NumberInputValueCaps; - if (HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS) - { - for (USHORT i = 0; i < capsLength; i++) - { - if (HidP_GetUsageValue( - HidP_Input, pValueCaps[i].UsagePage, 0, - pValueCaps[i].Range.UsageMin, &value, pPreparsedData, - (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) - { - continue; // if here then maybe something is up with HIDP_CAPS.NumberInputValueCaps - } - - //Console.Warning("Min/max %d/%d\t", pValueCaps[i].LogicalMin, pValueCaps[i].LogicalMax); - - //Get mapped axis for physical axis - uint16_t v = 0; - switch (pValueCaps[i].Range.UsageMin) - { - case HID_USAGE_GENERIC_X: //0x30 - case HID_USAGE_GENERIC_Y: - case HID_USAGE_GENERIC_Z: - case HID_USAGE_GENERIC_RX: - case HID_USAGE_GENERIC_RY: - case HID_USAGE_GENERIC_RZ: //0x35 - v = mapping->axisMap[pValueCaps[i].Range.UsageMin - HID_USAGE_GENERIC_X]; - break; - case HID_USAGE_GENERIC_HATSWITCH: - //Console.Warning("Hat: %02X\n", value); - v = mapping->axisMap[6]; - break; - } - - for (int j = 0; j < 2; j++) - { - if (!PLY_IS_MAPPED(j, v)) - continue; - - switch (PLY_GET_VALUE(j, v)) - { - case PAD_AXIS_X: // X-axis - //Console.Warning("X: %d\n", value); - // Need for logical min too? - //generic_data.axis_x = ((value - pValueCaps[i].LogicalMin) * 0x3FF) / (pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin); - if (subtype == WT_DRIVING_FORCE_PRO || subtype == WT_DRIVING_FORCE_PRO_1102) - mapping->data[j].steering = (value * 0x3FFF) / pValueCaps[i].LogicalMax; - else - //XXX Limit value range to 0..1023 if using 'generic' wheel descriptor - mapping->data[j].steering = (value * 0x3FF) / pValueCaps[i].LogicalMax; - break; - - case PAD_AXIS_Y: // Y-axis - //XXX Limit value range to 0..255 - mapping->data[j].clutch = (value * 0xFF) / pValueCaps[i].LogicalMax; - break; - - case PAD_AXIS_Z: // Z-axis - //Console.Warning("Z: %d\n", value); - //XXX Limit value range to 0..255 - mapping->data[j].throttle = (value * 0xFF) / pValueCaps[i].LogicalMax; - break; - - case PAD_AXIS_RZ: // Rotate-Z - //Console.Warning("Rz: %d\n", value); - //XXX Limit value range to 0..255 - mapping->data[j].brake = (value * 0xFF) / pValueCaps[i].LogicalMax; - break; - - case PAD_AXIS_HAT: // TODO Hat Switch - //Console.Warning("Hat: %02X\n", value); - //TODO 4 vs 8 direction hat switch - if (pValueCaps[i].LogicalMax == 4 && value < 4) - mapping->data[j].hatswitch = HATS_8TO4[value]; - else - mapping->data[j].hatswitch = value; - break; - } - } - } - } - - Error: - SAFE_FREE(pPreparsedData); - SAFE_FREE(pButtonCaps); - SAFE_FREE(pValueCaps); - } - - static void ParseRawInputKB(PRAWINPUT pRawInput, int subtype) - { - Mappings* mapping = nullptr; - - for (auto& it : mapVector) - { - if (!it.hidPath.compare(TEXT("Keyboard"))) - { - mapping = ⁢ - break; - } - } - - if (mapping == NULL) - return; - - for (uint32_t i = 0; i < PAD_BUTTON_COUNT; i++) - { - uint16_t btn = mapping->btnMap[i]; - for (int j = 0; j < 2; j++) - { - if (PLY_IS_MAPPED(j, btn)) - { - PS2WheelTypes wt = (PS2WheelTypes) subtype; - if (PLY_GET_VALUE(j, mapping->btnMap[i]) == pRawInput->data.keyboard.VKey) - { - uint32_t wtbtn = convert_wt_btn(wt, i); - if (pRawInput->data.keyboard.Flags & RI_KEY_BREAK) - mapping->data[j].buttons &= ~(1 << wtbtn); //unset - else /* if(pRawInput->data.keyboard.Flags == RI_KEY_MAKE) */ - mapping->data[j].buttons |= (1 << wtbtn); //set - } - } - } - } - - for (uint32_t i = 0; i < 4 /*PAD_HAT_COUNT*/; i++) - { - uint16_t btn = mapping->hatMap[i]; - for (int j = 0; j < 2; j++) - { - if (PLY_IS_MAPPED(j, btn)) - { - if (PLY_GET_VALUE(j, mapping->hatMap[i]) == pRawInput->data.keyboard.VKey) - if (pRawInput->data.keyboard.Flags & RI_KEY_BREAK) - mapping->data[j].hatswitch = 0x8; - else //if(pRawInput->data.keyboard.Flags == RI_KEY_MAKE) - mapping->data[j].hatswitch = HATS_8TO4[i]; - } - } - } - } - - void RawInputPad::ParseRawInput(PRAWINPUT pRawInput) - { - if (pRawInput->header.dwType == RIM_TYPEKEYBOARD) - ParseRawInputKB(pRawInput, Type()); - else if (pRawInput->header.dwType == RIM_TYPEHID) - ParseRawInputHID(pRawInput, Type()); - } - - int RawInputPad::Open() - { - PHIDP_PREPARSED_DATA pPreparsedData = nullptr; - HIDD_ATTRIBUTES attr; - - Close(); - - mappings.clear(); - LoadMappings(mDevType, mapVector); - - memset(&mOLRead, 0, sizeof(OVERLAPPED)); - memset(&mOLWrite, 0, sizeof(OVERLAPPED)); - memset(&mDataCopy, 0xFF, sizeof(mDataCopy)); - - mUsbHandle = INVALID_HANDLE_VALUE; - std::wstring path; - if (!LoadSetting(mDevType, mPort, APINAME, N_JOYSTICK, path)) - return 1; - - LoadSetting(mDevType, mPort, APINAME, N_WHEEL_PT, mDoPassthrough); - - mUsbHandle = CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - - if (mUsbHandle != INVALID_HANDLE_VALUE) - { - mOLRead.hEvent = CreateEvent(0, 0, 0, 0); - mOLWrite.hEvent = CreateEvent(0, 0, 0, 0); - - HidD_GetAttributes(mUsbHandle, &(attr)); - - bool isClassicLogitech = (attr.VendorID == PAD_VID) && (attr.ProductID != 0xC262); - bool isKeyboardmania = (attr.VendorID == 0x0507) && (attr.ProductID == 0x0010); - if (!isClassicLogitech && !isKeyboardmania) - { - Console.Warning("USB: Vendor is not Logitech or wheel is G920. Not sending force feedback commands for safety reasons.\n"); - mDoPassthrough = 0; - Close(); - } - else if (!mWriterThreadIsRunning) - { - if (mWriterThread.joinable()) - mWriterThread.join(); - mWriterThread = std::thread(RawInputPad::WriterThread, this); - } - - if (mDoPassthrough) - { - // for passthrough only - HidD_GetPreparsedData(mUsbHandle, &pPreparsedData); - HidP_GetCaps(pPreparsedData, &(mCaps)); - HidD_FreePreparsedData(pPreparsedData); - - if (!mReaderThreadIsRunning) - { - if (mReaderThread.joinable()) - mReaderThread.join(); - mReaderThread = std::thread(RawInputPad::ReaderThread, this); - } - } - - shared::rawinput::RegisterCallback(this); - return 0; - } - else - Console.Warning("USB: Could not open device '%s'.\nPassthrough and FFB will not work.\n", path.c_str()); - - return 0; - } - - int RawInputPad::Close() - { - if (mUsbHandle != INVALID_HANDLE_VALUE) - { - Reset(); - Sleep(100); // give WriterThread some time to write out Reset() commands - CloseHandle(mUsbHandle); - CloseHandle(mOLRead.hEvent); - CloseHandle(mOLWrite.hEvent); - } - - shared::rawinput::UnregisterCallback(this); - mUsbHandle = INVALID_HANDLE_VALUE; - return 0; - } - -// --------- -#include "raw-config-res.h" - - INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); - int RawInputPad::Configure(int port, const char* dev_type, void* data) - { - Win32Handles* h = (Win32Handles*)data; - INT_PTR res = RESULT_FAILED; - if (shared::rawinput::Initialize(h->hWnd)) - { - RawDlgConfig config(port, dev_type); - res = DialogBoxParam(h->hInst, MAKEINTRESOURCE(IDD_RAWCONFIG), h->hWnd, ConfigureRawDlgProc, (LPARAM)&config); - shared::rawinput::Uninitialize(); - } - return (int)res; - } - - } // namespace raw -} // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/raw/usb-pad-raw.h b/pcsx2/USB/usb-pad/raw/usb-pad-raw.h deleted file mode 100644 index c4373a2d45..0000000000 --- a/pcsx2/USB/usb-pad/raw/usb-pad-raw.h +++ /dev/null @@ -1,144 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2020 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#ifndef USBPADRAW_H -#define USBPADRAW_H -#include -#include -#include -#include "USB/usb-pad/padproxy.h" -#include "USB/usb-pad/usb-pad.h" -#include "USB/shared/rawinput_usb.h" -#include "USB/readerwriterqueue/readerwriterqueue.h" - -namespace usb_pad -{ - namespace raw - { - - static const char* APINAME = "rawinput"; - - class RawInputPad : public Pad, shared::rawinput::ParseRawInputCB - { - public: - RawInputPad(int port, const char* dev_type) - : Pad(port, dev_type) - , mDoPassthrough(false) - , mUsbHandle(INVALID_HANDLE_VALUE) - , mWriterThreadIsRunning(false) - , mReaderThreadIsRunning(false) - { - if (!InitHid()) - throw PadError("InitHid() failed!"); - } - ~RawInputPad() - { - Close(); - if (mWriterThread.joinable()) - mWriterThread.join(); - } - int Open(); - int Close(); - int TokenIn(uint8_t* buf, int len); - int TokenOut(const uint8_t* data, int len); - int Reset() - { - uint8_t reset[7] = {0}; - reset[0] = 0xF3; //stop forces - TokenOut(reset, sizeof(reset)); - return 0; - } - void ParseRawInput(PRAWINPUT pRawInput); - - static const TCHAR* Name() - { - return TEXT("Raw Input"); - } - - static int Configure(int port, const char* dev_type, void* data); - - protected: - static void WriterThread(void* ptr); - static void ReaderThread(void* ptr); - HIDP_CAPS mCaps; - HANDLE mUsbHandle = (HANDLE)-1; - OVERLAPPED mOLRead; - OVERLAPPED mOLWrite; - - int32_t mDoPassthrough; - wheel_data_t mDataCopy; - std::thread mWriterThread; - std::thread mReaderThread; - std::atomic mWriterThreadIsRunning; - std::atomic mReaderThreadIsRunning; - moodycamel::BlockingReaderWriterQueue, 32> mFFData; - moodycamel::BlockingReaderWriterQueue, 16> mReportData; //TODO 32 is random - }; - -/* -Layout: - 0x8000 bit means it is a valid mapping, - where value is PS2 button/axis and - array (Mappings::btnMap etc.) index is physical button/axis - (reversed for keyboard mappings). - [31..16] bits player 2 mapping - [15..0] bits player 1 mapping -*/ -//Maybe getting too convoluted -//Check for which player(s) the mapping is for -//Using MSB (right? :P) to indicate if valid mapping -#define PLY_IS_MAPPED(p, x) (x & (0x8000 << (16 * p))) -// Add owning player bits to mapping -#define PLY_SET_MAPPED(p, x) (((x & 0x7FFF) | 0x8000) << (16 * p)) -#define PLY_UNSET_MAPPED(p, x) (x & ~(0xFFFF << (16 * p))) -#define PLY_GET_VALUE(p, x) ((x >> (16 * p)) & 0x7FFF) - - //Joystick: btnMap/axisMap/hatMap[physical button] = ps2 button - //Keyboard: btnMap/axisMap/hatMap[ps2 button] = vkey - struct Mappings - { - uint32_t btnMap[MAX_BUTTONS]; - uint32_t axisMap[MAX_AXES]; - uint32_t hatMap[8]; - wheel_data_t data[2]; - std::wstring devName; -#if _WIN32 - std::wstring hidPath; -#endif - }; - - struct RawDlgConfig - { - int port; - const char* dev_type; - std::wstring player_joys[2]; - int32_t pt[2]{}; - RawDlgConfig(int p, const char* dev_type_) - : port(p) - , dev_type(dev_type_) - { - } - }; - - typedef std::vector MapVector; - static MapVector mapVector; - static std::map mappings; - - void LoadMappings(const char* dev_type, MapVector& maps); - void SaveMappings(const char* dev_type, MapVector& maps); - - } // namespace raw -} // namespace usb_pad -#endif diff --git a/pcsx2/USB/usb-pad/usb-pad-ff.cpp b/pcsx2/USB/usb-pad/usb-pad-ff.cpp index 3b601b09fe..f7fa848c55 100644 --- a/pcsx2/USB/usb-pad/usb-pad-ff.cpp +++ b/pcsx2/USB/usb-pad/usb-pad-ff.cpp @@ -19,8 +19,7 @@ namespace usb_pad { - - void SetConstantForce(FFDevice* ffdev, int force) + static void SetConstantForce(FFDevice* ffdev, int force) { //parsed_ff_data ff; @@ -28,7 +27,7 @@ namespace usb_pad ffdev->SetConstantForce(level); } - void SetSpringForce(FFDevice* ffdev, const spring& force, int caps) + static void SetSpringForce(FFDevice* ffdev, const spring& force, int caps) { parsed_ff_data ff; @@ -53,7 +52,7 @@ namespace usb_pad ffdev->SetSpringForce(ff); } - void SetDamperForce(FFDevice* ffdev, const damper& force, int caps) + static void SetDamperForce(FFDevice* ffdev, const damper& force, int caps) { parsed_ff_data ff; @@ -69,7 +68,7 @@ namespace usb_pad ffdev->SetDamperForce(ff); } - void SetFrictionForce(FFDevice* ffdev, const friction& frict) + static void SetFrictionForce(FFDevice* ffdev, const friction& frict) { parsed_ff_data ff; @@ -88,21 +87,21 @@ namespace usb_pad ffdev->SetFrictionForce(ff); } - void SetAutoCenter(FFDevice* ffdev, const autocenter& effect) + static void SetAutoCenter(FFDevice* ffdev, const autocenter& effect) { DevCon.WriteLn("%s: k1 %d k2 %d clip %d\n", __func__, effect.k1, effect.k2, effect.clip); ffdev->SetAutoCenter((effect.k1 * effect.clip / 255) * 100 / 255); // FIXME } // Unless passing ff packets straight to a device, parse it here - void Pad::ParseFFData(const ff_data* ffdata, bool isDFP) + void PadState::ParseFFData(const ff_data* ffdata, bool isDFP) { if (!mFFdev) return; DevCon.WriteLn("FFB %02X, %02X, %02X, %02X : %02X, %02X, %02X, %02X", - ffdata->cmdslot, ffdata->type, ffdata->u.params[0], ffdata->u.params[1], - ffdata->u.params[2], ffdata->u.params[3], ffdata->u.params[4], ffdata->padd0); + ffdata->cmdslot, ffdata->type, ffdata->u.params[0], ffdata->u.params[1], + ffdata->u.params[2], ffdata->u.params[3], ffdata->u.params[4], ffdata->padd0); if (ffdata->cmdslot != CMD_EXTENDED_CMD) { @@ -145,22 +144,22 @@ namespace usb_pad t++; force = (std::min)((std::max)(force + t - 128, -128), 127); } - SetConstantForce(mFFdev, 128 + force); + SetConstantForce(mFFdev.get(), 128 + force); } else { for (int i = 0; i < 4; i++) { if (slots == (1 << i)) - SetConstantForce(mFFdev, ffdata->u.params[i]); + SetConstantForce(mFFdev.get(), ffdata->u.params[i]); } } break; case FTYPE_SPRING: - SetSpringForce(mFFdev, ffdata->u.spring, isDFP ? 0 : FF_LG_CAPS_OLD_LOW_RES_COEF); + SetSpringForce(mFFdev.get(), ffdata->u.spring, isDFP ? 0 : FF_LG_CAPS_OLD_LOW_RES_COEF); break; case FTYPE_HIGH_RESOLUTION_SPRING: - SetSpringForce(mFFdev, ffdata->u.spring, FF_LG_CAPS_HIGH_RES_COEF | FF_LG_CAPS_HIGH_RES_DEADBAND); + SetSpringForce(mFFdev.get(), ffdata->u.spring, FF_LG_CAPS_HIGH_RES_COEF | FF_LG_CAPS_HIGH_RES_DEADBAND); break; case FTYPE_VARIABLE: //Ramp-like //SetRampVariable(mFFdev, ffdata->u.variable); @@ -172,13 +171,13 @@ namespace usb_pad if (warned == 0) { DevCon.WriteLn("variable force cannot be converted to constant force (l1=%hhu, t1=%hhu, s1=%hhu, d1=%hhu\n", - ffdata->u.variable.l1, ffdata->u.variable.t1, ffdata->u.variable.s1, ffdata->u.variable.d1); + ffdata->u.variable.l1, ffdata->u.variable.t1, ffdata->u.variable.s1, ffdata->u.variable.d1); warned = 1; } } else { - SetConstantForce(mFFdev, ffdata->u.variable.l1); + SetConstantForce(mFFdev.get(), ffdata->u.variable.l1); } } else if (slots & (1 << 2)) @@ -188,30 +187,30 @@ namespace usb_pad if (warned == 0) { DevCon.WriteLn("variable force cannot be converted to constant force (l2=%hhu, t2=%hhu, s2=%hhu, d2=%hhu\n", - ffdata->u.variable.l2, ffdata->u.variable.t2, ffdata->u.variable.s2, ffdata->u.variable.d2); + ffdata->u.variable.l2, ffdata->u.variable.t2, ffdata->u.variable.s2, ffdata->u.variable.d2); warned = 1; } } else { - SetConstantForce(mFFdev, ffdata->u.variable.l2); + SetConstantForce(mFFdev.get(), ffdata->u.variable.l2); } } break; case FTYPE_FRICTION: - SetFrictionForce(mFFdev, ffdata->u.friction); + SetFrictionForce(mFFdev.get(), ffdata->u.friction); break; case FTYPE_DAMPER: - SetDamperForce(mFFdev, ffdata->u.damper, 0); + SetDamperForce(mFFdev.get(), ffdata->u.damper, 0); break; case FTYPE_HIGH_RESOLUTION_DAMPER: caps = FF_LG_CAPS_HIGH_RES_COEF; if (isDFP) caps |= FF_LG_CAPS_DAMPER_CLIP; - SetDamperForce(mFFdev, ffdata->u.damper, caps); + SetDamperForce(mFFdev.get(), ffdata->u.damper, caps); break; case FTYPE_AUTO_CENTER_SPRING: - SetAutoCenter(mFFdev, ffdata->u.autocenter); + SetAutoCenter(mFFdev.get(), ffdata->u.autocenter); break; default: DevCon.WriteLn("CMD_DOWNLOAD_AND_PLAY: unhandled force type 0x%02X in slots 0x%02X\n", ffdata->type, slots); @@ -264,7 +263,7 @@ namespace usb_pad if (slots == 0x0F) { //just release force - SetConstantForce(mFFdev, 127); + SetConstantForce(mFFdev.get(), 127); } else { @@ -301,7 +300,7 @@ namespace usb_pad { } DevCon.WriteLn("CMD_EXTENDED: unhandled cmd 0x%02X%02X%02X\n", - ffdata->type, ffdata->u.params[0], ffdata->u.params[1]); + ffdata->type, ffdata->u.params[0], ffdata->u.params[1]); } } diff --git a/pcsx2/USB/usb-pad/usb-pad-sdl-ff.cpp b/pcsx2/USB/usb-pad/usb-pad-sdl-ff.cpp new file mode 100644 index 0000000000..c357233088 --- /dev/null +++ b/pcsx2/USB/usb-pad/usb-pad-sdl-ff.cpp @@ -0,0 +1,337 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2020 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "USB/usb-pad/usb-pad-sdl-ff.h" +#include "Frontend/InputManager.h" +#include "common/Console.h" +#include "fmt/format.h" +#include + +#ifdef SDL_BUILD + +namespace usb_pad +{ + SDLFFDevice::SDLFFDevice(SDL_Haptic* haptic) + : m_haptic(haptic) + { + } + + SDLFFDevice::~SDLFFDevice() + { + if (m_haptic) + { + DestroyEffects(); + + SDL_HapticClose(m_haptic); + m_haptic = nullptr; + } + } + + std::unique_ptr SDLFFDevice::Create(const std::string_view& device) + { + SDLInputSource* source = static_cast(InputManager::GetInputSourceInterface(InputSourceType::SDL)); + if (!source) + return nullptr; + + SDL_Joystick* joystick = source->GetJoystickForDevice(device); + if (!joystick) + { + Console.Error(fmt::format("No SDL_Joystick for {}. Cannot use FF.", device)); + return nullptr; + } + + SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick); + if (!haptic) + { + Console.Error(fmt::format("Haptic is not supported on {}.", device)); + return nullptr; + } + + std::unique_ptr ret(new SDLFFDevice(haptic)); + ret->CreateEffects(device); + return ret; + } + + void SDLFFDevice::CreateEffects(const std::string_view& device) + { + constexpr u32 length = 1000; // good enough? + + const unsigned int supported = SDL_HapticQuery(m_haptic); + if (supported & SDL_HAPTIC_CONSTANT) + { + m_constant_effect.type = SDL_HAPTIC_CONSTANT; + m_constant_effect.constant.direction.type = SDL_HAPTIC_CARTESIAN; + m_constant_effect.constant.length = length; + + m_constant_effect_id = SDL_HapticNewEffect(m_haptic, &m_constant_effect); + if (m_constant_effect_id < 0) + Console.Error("SDL_HapticNewEffect() for constant failed: %s", SDL_GetError()); + } + else + { + Console.Warning(fmt::format("(SDLFFDevice) Constant effect is not supported on '{}'", device)); + } + + if (supported & SDL_HAPTIC_SPRING) + { + m_spring_effect.type = SDL_HAPTIC_SPRING; + m_spring_effect.condition.direction.type = SDL_HAPTIC_CARTESIAN; + m_spring_effect.condition.length = length; + + m_spring_effect_id = SDL_HapticNewEffect(m_haptic, &m_spring_effect); + if (m_spring_effect_id < 0) + Console.Error("SDL_HapticNewEffect() for spring failed: %s", SDL_GetError()); + } + else + { + Console.Warning(fmt::format("(SDLFFDevice) Spring effect is not supported on '{}'", device)); + } + + if (supported & SDL_HAPTIC_DAMPER) + { + m_damper_effect.type = SDL_HAPTIC_DAMPER; + m_damper_effect.condition.direction.type = SDL_HAPTIC_CARTESIAN; + m_damper_effect.condition.length = length; + + m_damper_effect_id = SDL_HapticNewEffect(m_haptic, &m_damper_effect); + if (m_damper_effect_id < 0) + Console.Error("SDL_HapticNewEffect() for damper failed: %s", SDL_GetError()); + } + else + { + Console.Warning(fmt::format("(SDLFFDevice) Damper effect is not supported on '{}'", device)); + } + + if (supported & SDL_HAPTIC_FRICTION) + { + m_friction_effect.type = SDL_HAPTIC_FRICTION; + m_friction_effect.condition.direction.type = SDL_HAPTIC_CARTESIAN; + m_friction_effect.condition.length = length; + + m_friction_effect_id = SDL_HapticNewEffect(m_haptic, &m_friction_effect); + if (m_friction_effect_id < 0) + Console.Error("SDL_HapticNewEffect() for friction failed: %s", SDL_GetError()); + } + else + { + Console.Warning(fmt::format("(SDLFFDevice) Friction effect is not supported on '{}'", device)); + } + + m_autocenter_supported = (supported & SDL_HAPTIC_AUTOCENTER) != 0; + if (!m_autocenter_supported) + Console.Warning(fmt::format("(SDLFFDevice) Autocenter effect is not supported on '{}'", device)); + } + + void SDLFFDevice::DestroyEffects() + { + if (m_friction_effect_id >= 0) + { + if (m_friction_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_friction_effect_id); + m_friction_effect_running = false; + } + SDL_HapticDestroyEffect(m_haptic, m_friction_effect_id); + m_friction_effect_id = -1; + } + + if (m_damper_effect_id >= 0) + { + if (m_damper_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_damper_effect_id); + m_damper_effect_running = false; + } + SDL_HapticDestroyEffect(m_haptic, m_damper_effect_id); + m_damper_effect_id = -1; + } + + if (m_spring_effect_id >= 0) + { + if (m_spring_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_spring_effect_id); + m_spring_effect_running = false; + } + SDL_HapticDestroyEffect(m_haptic, m_spring_effect_id); + m_spring_effect_id = -1; + } + + if (m_constant_effect_id >= 0) + { + if (m_constant_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_constant_effect_id); + m_constant_effect_running = false; + } + SDL_HapticDestroyEffect(m_haptic, m_constant_effect_id); + m_constant_effect_id = -1; + } + } + + void SDLFFDevice::SetConstantForce(int level) + { + if (m_constant_effect_id < 0) + return; + + const s16 new_level = static_cast(std::clamp(level, -32768, 32767)); + if (m_constant_effect.constant.level != level) + { + m_constant_effect.constant.level = new_level; + if (SDL_HapticUpdateEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0) + Console.Warning("SDL_HapticUpdateEffect() for constant failed: %s", SDL_GetError()); + } + + if (!m_constant_effect_running && SDL_HapticRunEffect(m_haptic, m_constant_effect_id, SDL_HAPTIC_INFINITY) == 0) + m_constant_effect_running = true; + else + Console.Error("SDL_HapticRunEffect() for constant failed: %s", SDL_GetError()); + } + + template + static u16 ClampU16(T val) + { + return static_cast(std::clamp(val, 0, 0xFFFF)); + } + + void SDLFFDevice::SetSpringForce(const parsed_ff_data& ff) + { + if (m_spring_effect_id < 0) + return; + + m_spring_effect.condition.left_sat[0] = ClampU16(ff.u.condition.left_saturation); + m_spring_effect.condition.left_coeff[0] = ClampU16(ff.u.condition.left_coeff); + m_spring_effect.condition.right_sat[0] = ClampU16(ff.u.condition.right_saturation); + m_spring_effect.condition.right_coeff[0] = ClampU16(ff.u.condition.right_coeff); + m_spring_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband); + m_spring_effect.condition.center[0] = ClampU16(ff.u.condition.center); + + if (SDL_HapticUpdateEffect(m_haptic, m_spring_effect_id, &m_spring_effect) != 0) + Console.Warning("SDL_HapticUpdateEffect() for spring failed: %s", SDL_GetError()); + + if (!m_spring_effect_running && SDL_HapticRunEffect(m_haptic, m_spring_effect_id, SDL_HAPTIC_INFINITY) == 0) + m_spring_effect_running = true; + else + Console.Warning("SDL_HapticRunEffect() for spring failed: %s", SDL_GetError()); + } + + void SDLFFDevice::SetDamperForce(const parsed_ff_data& ff) + { + if (m_damper_effect_id < 0) + return; + + m_damper_effect.condition.left_sat[0] = ClampU16(ff.u.condition.left_saturation); + m_damper_effect.condition.left_coeff[0] = ClampU16(ff.u.condition.left_coeff); + m_damper_effect.condition.right_sat[0] = ClampU16(ff.u.condition.right_saturation); + m_damper_effect.condition.right_coeff[0] = ClampU16(ff.u.condition.right_coeff); + m_damper_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband); + m_damper_effect.condition.center[0] = ClampU16(ff.u.condition.center); + + if (SDL_HapticUpdateEffect(m_haptic, m_damper_effect_id, &m_damper_effect) != 0) + Console.Warning("SDL_HapticUpdateEffect() for damper failed: %s", SDL_GetError()); + + if (!m_damper_effect_running && SDL_HapticRunEffect(m_haptic, m_damper_effect_id, SDL_HAPTIC_INFINITY) == 0) + m_damper_effect_running = true; + else + Console.Warning("SDL_HapticRunEffect() for damper failed: %s", SDL_GetError()); + } + + void SDLFFDevice::SetFrictionForce(const parsed_ff_data& ff) + { + if (m_friction_effect_id < 0) + return; + + m_friction_effect.condition.left_sat[0] = ClampU16(ff.u.condition.left_saturation); + m_friction_effect.condition.left_coeff[0] = ClampU16(ff.u.condition.left_coeff); + m_friction_effect.condition.right_sat[0] = ClampU16(ff.u.condition.right_saturation); + m_friction_effect.condition.right_coeff[0] = ClampU16(ff.u.condition.right_coeff); + m_friction_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband); + m_friction_effect.condition.center[0] = ClampU16(ff.u.condition.center); + + if (SDL_HapticUpdateEffect(m_haptic, m_friction_effect_id, &m_friction_effect) != 0) + Console.Warning("SDL_HapticUpdateEffect() for friction failed: %s", SDL_GetError()); + + if (!m_friction_effect_running && SDL_HapticRunEffect(m_haptic, m_friction_effect_id, SDL_HAPTIC_INFINITY) == 0) + m_friction_effect_running = true; + else + Console.Warning("SDL_HapticRunEffect() for friction failed: %s", SDL_GetError()); + } + + void SDLFFDevice::SetAutoCenter(int value) + { + if (m_autocenter_supported) + { + if (SDL_HapticSetAutocenter(m_haptic, value) != 0) + Console.Warning("SDL_HapticSetAutocenter() failed: %s", SDL_GetError()); + } + } + + void SDLFFDevice::DisableForce(EffectID force) + { + switch (force) + { + case EFF_CONSTANT: + { + if (m_constant_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_constant_effect_id); + m_constant_effect_running = false; + } + } + break; + + case EFF_SPRING: + { + if (m_spring_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_spring_effect_id); + m_spring_effect_running = false; + } + } + break; + + case EFF_DAMPER: + { + if (m_damper_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_damper_effect_id); + m_damper_effect_running = false; + } + } + break; + + case EFF_FRICTION: + { + if (m_friction_effect_running) + { + SDL_HapticStopEffect(m_haptic, m_friction_effect_id); + m_friction_effect_running = false; + } + } + break; + + case EFF_RUMBLE: + // Not implemented? + break; + + default: + break; + } + } + +} // namespace usb_pad + +#endif \ No newline at end of file diff --git a/pcsx2/USB/usb-pad/usb-pad-sdl-ff.h b/pcsx2/USB/usb-pad/usb-pad-sdl-ff.h new file mode 100644 index 0000000000..4b3fc8edd8 --- /dev/null +++ b/pcsx2/USB/usb-pad/usb-pad-sdl-ff.h @@ -0,0 +1,68 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "USB/usb-pad/usb-pad.h" + +#ifdef SDL_BUILD + +#include "Frontend/SDLInputSource.h" + +namespace usb_pad +{ + class SDLFFDevice : public FFDevice + { + public: + ~SDLFFDevice() override; + + static std::unique_ptr Create(const std::string_view& device); + + void SetConstantForce(int level) override; + void SetSpringForce(const parsed_ff_data& ff) override; + void SetDamperForce(const parsed_ff_data& ff) override; + void SetFrictionForce(const parsed_ff_data& ff) override; + void SetAutoCenter(int value) override; + void DisableForce(EffectID force) override; + + private: + SDLFFDevice(SDL_Haptic* haptic); + + void CreateEffects(const std::string_view& device); + void DestroyEffects(); + + SDL_Haptic* m_haptic = nullptr; + + SDL_HapticEffect m_constant_effect = {}; + int m_constant_effect_id = -1; + bool m_constant_effect_running = false; + + SDL_HapticEffect m_spring_effect = {}; + int m_spring_effect_id = -1; + bool m_spring_effect_running = false; + + SDL_HapticEffect m_damper_effect = {}; + int m_damper_effect_id = -1; + bool m_damper_effect_running = false; + + SDL_HapticEffect m_friction_effect = {}; + int m_friction_effect_id = -1; + bool m_friction_effect_running = false; + + bool m_autocenter_supported = false; + }; +} // namespace usb_pad + +#endif diff --git a/pcsx2/USB/usb-pad/usb-pad.cpp b/pcsx2/USB/usb-pad/usb-pad.cpp index 94ce73bdf8..c0eae6ea35 100644 --- a/pcsx2/USB/usb-pad/usb-pad.cpp +++ b/pcsx2/USB/usb-pad/usb-pad.cpp @@ -14,14 +14,17 @@ */ #include "PrecompiledHeader.h" -#include "padproxy.h" #include "usb-pad.h" -#include "USB/qemu-usb/desc.h" -#include "USB/shared/inifile_usb.h" +#include "USB/qemu-usb/USBinternal.h" +#include "USB/USB.h" +#include "StateWrapper.h" + +#ifdef SDL_BUILD +#include "USB/usb-pad/usb-pad-sdl-ff.h" +#endif namespace usb_pad { - static const USBDescStrings df_desc_strings = { "", "Logitech Driving Force", @@ -38,7 +41,7 @@ namespace usb_pad static const USBDescStrings gtf_desc_strings = { "", - "Logitech", //actual index @ 0x04 + "Logitech", //actual index @ 0x04 "Logitech GT Force" //actual index @ 0x20 }; @@ -59,103 +62,518 @@ namespace usb_pad "", "KONAMI"}; - static const USBDescStrings gametrak_desc_strings = { - "", - "In2Games Ltd.", - "Game-Trak V1.3"}; - - static const USBDescStrings realplay_desc_strings = { - "", - "In2Games", - "Real Play"}; - - std::list PadDevice::ListAPIs() + static gsl::span GetWheelBindings(PS2WheelTypes wt) { - return RegisterPad::instance().Names(); - } - - const TCHAR* PadDevice::LongAPIName(const std::string& name) - { - auto proxy = RegisterPad::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } - - std::list RBDrumKitDevice::ListAPIs() - { - return PadDevice::ListAPIs(); - } - - const TCHAR* RBDrumKitDevice::LongAPIName(const std::string& name) - { - return PadDevice::LongAPIName(name); - } - - std::list BuzzDevice::ListAPIs() - { - return PadDevice::ListAPIs(); - } - - const TCHAR* BuzzDevice::LongAPIName(const std::string& name) - { - return PadDevice::LongAPIName(name); - } - - std::list KeyboardmaniaDevice::ListAPIs() - { - return PadDevice::ListAPIs(); - } - - const TCHAR* KeyboardmaniaDevice::LongAPIName(const std::string& name) - { - return PadDevice::LongAPIName(name); - } - - std::list GametrakDevice::ListAPIs() - { - return PadDevice::ListAPIs(); - } - - const TCHAR* GametrakDevice::LongAPIName(const std::string& name) - { - return PadDevice::LongAPIName(name); - } - - std::list RealPlayDevice::ListAPIs() - { - return PadDevice::ListAPIs(); - } - - const TCHAR* RealPlayDevice::LongAPIName(const std::string& name) - { - return PadDevice::LongAPIName(name); - } - -#ifdef _DEBUG - void PrintBits(void* data, int size) - { - std::vector buf(size * 8 + 1 + size); - unsigned char* bits = buf.data(); - unsigned char* ptrD = (unsigned char*)data; - unsigned char* ptrB = bits; - for (int i = 0; i < size * 8; i++) + switch (wt) { - *(ptrB++) = '0' + (*(ptrD + i / 8) & (1 << (i % 8)) ? 1 : 0); - if (i % 8 == 7) - *(ptrB++) = ' '; + case WT_GENERIC: + { + static constexpr const InputBindingInfo bindings[] = { + {"SteeringLeft", "Steering Left", InputBindingInfo::Type::HalfAxis, CID_STEERING_L, GenericInputBinding::LeftStickLeft}, + {"SteeringRight", "Steering Right", InputBindingInfo::Type::HalfAxis, CID_STEERING_R, GenericInputBinding::LeftStickRight}, + {"Throttle", "Throttle", InputBindingInfo::Type::HalfAxis, CID_THROTTLE, GenericInputBinding::R2}, + {"Brake", "Brake", InputBindingInfo::Type::HalfAxis, CID_BRAKE, GenericInputBinding::L2}, + {"DPadUp", "D-Pad Up", InputBindingInfo::Type::Button, CID_DPAD_UP, GenericInputBinding::DPadUp}, + {"DPadDown", "D-Pad Down", InputBindingInfo::Type::Button, CID_DPAD_DOWN, GenericInputBinding::DPadDown}, + {"DPadLeft", "D-Pad Left", InputBindingInfo::Type::Button, CID_DPAD_LEFT, GenericInputBinding::DPadLeft}, + {"DPadRight", "D-Pad Right", InputBindingInfo::Type::Button, CID_DPAD_RIGHT, GenericInputBinding::DPadRight}, + {"Cross", "Cross", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::Cross}, + {"Square", "Square", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Square}, + {"Circle", "Circle", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Circle}, + {"Triangle", "Triangle", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Triangle}, + {"L1", "L1", InputBindingInfo::Type::Button, CID_BUTTON5, GenericInputBinding::L1}, + {"R1", "R1", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::R1}, + {"L2", "L2", InputBindingInfo::Type::Button, CID_BUTTON7, GenericInputBinding::Unknown}, // used L2 for brake + {"R2", "R2", InputBindingInfo::Type::Button, CID_BUTTON6, GenericInputBinding::Unknown}, // used R2 for throttle + {"Select", "Select", InputBindingInfo::Type::Button, CID_BUTTON8, GenericInputBinding::Select}, + {"Start", "Start", InputBindingInfo::Type::Button, CID_BUTTON9, GenericInputBinding::Start}, + {"FFDevice", "Force Feedback", InputBindingInfo::Type::Device, 0, GenericInputBinding::Unknown}, + }; + + return bindings; + } + + case WT_DRIVING_FORCE_PRO: + case WT_DRIVING_FORCE_PRO_1102: + { + static constexpr const InputBindingInfo bindings[] = { + {"SteeringLeft", "Steering Left", InputBindingInfo::Type::HalfAxis, CID_STEERING_L, GenericInputBinding::LeftStickLeft}, + {"SteeringRight", "Steering Right", InputBindingInfo::Type::HalfAxis, CID_STEERING_R, GenericInputBinding::LeftStickRight}, + {"Throttle", "Throttle", InputBindingInfo::Type::HalfAxis, CID_THROTTLE, GenericInputBinding::R2}, + {"Brake", "Brake", InputBindingInfo::Type::HalfAxis, CID_BRAKE, GenericInputBinding::L2}, + {"DPadUp", "D-Pad Up", InputBindingInfo::Type::Button, CID_DPAD_UP, GenericInputBinding::DPadUp}, + {"DPadDown", "D-Pad Down", InputBindingInfo::Type::Button, CID_DPAD_DOWN, GenericInputBinding::DPadDown}, + {"DPadLeft", "D-Pad Left", InputBindingInfo::Type::Button, CID_DPAD_LEFT, GenericInputBinding::DPadLeft}, + {"DPadRight", "D-Pad Right", InputBindingInfo::Type::Button, CID_DPAD_RIGHT, GenericInputBinding::DPadRight}, + {"Cross", "Cross", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::Cross}, + {"Square", "Square", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Square}, + {"Circle", "Circle", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Circle}, + {"Triangle", "Triangle", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Triangle}, + {"R1", "Shift Up / R1", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::R1}, + {"L1", "Shift Down / L1", InputBindingInfo::Type::Button, CID_BUTTON5, GenericInputBinding::L1}, + {"Select", "Select", InputBindingInfo::Type::Button, CID_BUTTON8, GenericInputBinding::Select}, + {"Start", "Start", InputBindingInfo::Type::Button, CID_BUTTON9, GenericInputBinding::Start}, + {"L2", "L2", InputBindingInfo::Type::Button, CID_BUTTON7, GenericInputBinding::Unknown}, // used L2 for brake + {"R2", "R2", InputBindingInfo::Type::Button, CID_BUTTON6, GenericInputBinding::Unknown}, // used R2 for throttle + {"L3", "L3", InputBindingInfo::Type::Button, CID_BUTTON11, GenericInputBinding::L3}, + {"R3", "R3", InputBindingInfo::Type::Button, CID_BUTTON10, GenericInputBinding::R3}, + {"FFDevice", "Force Feedback", InputBindingInfo::Type::Device, 0, GenericInputBinding::Unknown}, + }; + + return bindings; + } + + case WT_GT_FORCE: + { + static constexpr const InputBindingInfo bindings[] = { + {"SteeringLeft", "Steering Left", InputBindingInfo::Type::HalfAxis, CID_STEERING_L, GenericInputBinding::LeftStickLeft}, + {"SteeringRight", "Steering Right", InputBindingInfo::Type::HalfAxis, CID_STEERING_R, GenericInputBinding::LeftStickRight}, + {"Throttle", "Throttle", InputBindingInfo::Type::HalfAxis, CID_THROTTLE, GenericInputBinding::R2}, + {"Brake", "Brake", InputBindingInfo::Type::HalfAxis, CID_BRAKE, GenericInputBinding::L2}, + {"MenuUp", "Menu Up", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::DPadUp}, + {"MenuDown", "Menu Down", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::DPadDown}, + {"X", "X", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Square}, + {"Y", "Y", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Triangle}, + {"A", "A", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::Cross}, + {"B", "B", InputBindingInfo::Type::Button, CID_BUTTON5, GenericInputBinding::Circle}, + {"FFDevice", "Force Feedback", InputBindingInfo::Type::Device, 0, GenericInputBinding::Unknown}, + }; + + return bindings; + } + + default: + { + return {}; + } } - *ptrB = '\0'; } -#else -#define PrintBits(...) -#define DbgPrint(...) -#endif //_DEBUG - - uint32_t gametrak_compute_key(uint32_t* key) + static gsl::span GetWheelSettings(PS2WheelTypes wt) { - uint32_t ret = 0; + if (wt <= WT_GT_FORCE) + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::Integer, "SteeringSmoothing", "Steering Smoothing", + "Smooths out changes in steering to the specified percentage per poll. Needed for using keyboards.", + "0", "0", "100", "1", "%d%%", nullptr, nullptr, 1.0f}, + }; + + return info; + } + else + { + return {}; + } + } + + PadState::PadState(u32 port_, PS2WheelTypes type_) + : port(port_) + , type(type_) + { + if (type_ == WT_DRIVING_FORCE_PRO || type_ == WT_DRIVING_FORCE_PRO_1102) + steering_range = 0x3FFF >> 1; + else if (type_ == WT_SEGA_SEAMIC) + steering_range = 0xFF >> 1; + else + steering_range = 0x3FF >> 1; + + steering_step = std::numeric_limits::max(); + + // steering starts in the center + data.last_steering = steering_range; + data.steering = steering_range; + + // throttle/brake start unpressed + data.throttle = 255; + data.brake = 255; + + Reset(); + } + + PadState::~PadState() = default; + + void PadState::UpdateSettings(SettingsInterface& si, const char* devname) + { + const s32 smoothing_percent = USB::GetConfigInt(si, port, devname, "SteeringSmoothing", 0); + if (smoothing_percent <= 0) + { + // none, allow any amount of change + steering_step = std::numeric_limits::max(); + } + else + { + steering_step = static_cast(std::clamp((steering_range * smoothing_percent) / 100, + 1, std::numeric_limits::max())); + } + + if (HasFF()) + { + const std::string ffdevname(USB::GetConfigString(si, port, devname, "FFDevice")); + if (ffdevname != mFFdevName) + { + mFFdev.reset(); + mFFdevName = std::move(ffdevname); + OpenFFDevice(); + } + } + } + + void PadState::Reset() + { + data.steering = steering_range; + mFFstate = {}; + } + + int PadState::TokenIn(u8* buf, int len) + { + // TODO: This is still pretty gross and needs cleaning up. + + struct wheel_lohi + { + u32 lo; + u32 hi; + }; + + wheel_lohi* w = reinterpret_cast(buf); + std::memset(w, 0, 8); + + switch (type) + { + case WT_GENERIC: + { + UpdateSteering(); + UpdateHatSwitch(); + + DbgCon.WriteLn("Steering: %d Throttle: %d Brake: %d Buttons: %d", + data.steering, data.throttle, data.brake, data.buttons); + + w->lo = data.steering & 0x3FF; + w->lo |= (data.buttons & 0xFFF) << 10; + w->lo |= 0xFF << 24; + + w->hi = (data.hatswitch & 0xF); + w->hi |= (data.throttle & 0xFF) << 8; + w->hi |= (data.brake & 0xFF) << 16; + + return len; + } + + case WT_GT_FORCE: + { + UpdateSteering(); + UpdateHatSwitch(); + + w->lo = data.steering & 0x3FF; + w->lo |= (data.buttons & 0xFFF) << 10; + w->lo |= 0xFF << 24; + + w->hi = (data.throttle & 0xFF); + w->hi |= (data.brake & 0xFF) << 8; + + return len; + } + + case WT_DRIVING_FORCE_PRO: + { + UpdateSteering(); + UpdateHatSwitch(); + + w->lo = data.steering & 0x3FFF; + w->lo |= (data.buttons & 0x3FFF) << 14; + w->lo |= (data.hatswitch & 0xF) << 28; + + w->hi = 0x00; + w->hi |= data.throttle << 8; + w->hi |= data.brake << 16; //axis_rz + w->hi |= 0x11 << 24; //enables wheel and pedals? + + return len; + } + + case WT_DRIVING_FORCE_PRO_1102: + { + UpdateSteering(); + UpdateHatSwitch(); + + // what's up with the bitmap? + // xxxxxxxx xxxxxxbb bbbbbbbb bbbbhhhh ???????? ?01zzzzz 1rrrrrr1 10001000 + w->lo = data.steering & 0x3FFF; + w->lo |= (data.buttons & 0x3FFF) << 14; + w->lo |= (data.hatswitch & 0xF) << 28; + + w->hi = 0x00; + //w->hi |= 0 << 9; //bit 9 must be 0 + w->hi |= (1 | (data.throttle * 0x3F) / 0xFF) << 10; //axis_z + w->hi |= 1 << 16; //bit 16 must be 1 + w->hi |= ((0x3F - (data.brake * 0x3F) / 0xFF) & 0x3F) << 17; //axis_rz + w->hi |= 1 << 23; //bit 23 must be 1 + w->hi |= 0x11 << 24; //enables wheel and pedals? + + return len; + } + + case WT_ROCKBAND1_DRUMKIT: + { + UpdateHatSwitch(); + + w->lo = (data.buttons & 0xFFF); + w->lo |= (data.hatswitch & 0xF) << 16; + + return len; + } + + case WT_BUZZ_CONTROLLER: + { + // https://gist.github.com/Lewiscowles1986/eef220dac6f0549e4702393a7b9351f6 + buf[0] = 0x7f; + buf[1] = 0x7f; + buf[2] = data.buttons & 0xff; + buf[3] = (data.buttons >> 8) & 0xff; + buf[4] = 0xf0 | ((data.buttons >> 16) & 0xf); + + return 5; + } + + case WT_SEGA_SEAMIC: + { + UpdateSteering(); + UpdateHatSwitch(); + + buf[0] = data.steering & 0xFF; + buf[1] = data.throttle & 0xFF; + buf[2] = data.brake & 0xFF; + buf[3] = data.hatswitch & 0x0F; // 4bits? + buf[3] |= (data.buttons & 0x0F) << 4; // 4 bits // TODO Or does it start at buf[4]? + buf[4] = (data.buttons >> 4) & 0x3F; // 10 - 4 = 6 bits + + return len; + } + + case WT_KEYBOARDMANIA_CONTROLLER: + { + buf[0] = 0x3F; + buf[1] = data.buttons & 0xFF; + buf[2] = (data.buttons >> 8) & 0xFF; + buf[3] = (data.buttons >> 16) & 0xFF; + buf[4] = (data.buttons >> 24) & 0xFF; + + return len; + } + + default: + { + return len; + } + } + } + + int PadState::TokenOut(const u8* data, int len) + { + const ff_data* ffdata = reinterpret_cast(data); + bool hires = (type == WT_DRIVING_FORCE_PRO || type == WT_DRIVING_FORCE_PRO_1102); + ParseFFData(ffdata, hires); + return len; + } + + float PadState::GetBindValue(u32 bind_index) const + { + switch (bind_index) + { + case CID_STEERING_L: + return static_cast(data.steering_left) / static_cast(steering_range); + + case CID_STEERING_R: + return static_cast(data.steering_right) / static_cast(steering_range); + + case CID_THROTTLE: + return 1.0f - (static_cast(data.throttle) / 255.0f); + + case CID_BRAKE: + return 1.0f - (static_cast(data.brake) / 255.0f); + + case CID_DPAD_UP: + return static_cast(data.hat_up); + + case CID_DPAD_DOWN: + return static_cast(data.hat_down); + + case CID_DPAD_LEFT: + return static_cast(data.hat_left); + + case CID_DPAD_RIGHT: + return static_cast(data.hat_right); + + case CID_BUTTON0: + case CID_BUTTON1: + case CID_BUTTON2: + case CID_BUTTON3: + case CID_BUTTON5: + case CID_BUTTON4: + case CID_BUTTON7: + case CID_BUTTON6: + case CID_BUTTON8: + case CID_BUTTON9: + case CID_BUTTON10: + case CID_BUTTON11: + case CID_BUTTON12: + case CID_BUTTON13: + case CID_BUTTON14: + case CID_BUTTON15: + case CID_BUTTON16: + case CID_BUTTON17: + case CID_BUTTON18: + case CID_BUTTON19: + case CID_BUTTON20: + case CID_BUTTON21: + case CID_BUTTON22: + case CID_BUTTON23: + case CID_BUTTON24: + { + const u32 mask = (1u << (bind_index - CID_BUTTON0)); + return ((data.buttons & mask) != 0u) ? 1.0f : 0.0f; + } + + default: + return 0.0f; + } + } + + void PadState::SetBindValue(u32 bind_index, float value) + { + switch (bind_index) + { + case CID_STEERING_L: + data.steering_left = static_cast(std::lroundf(value * static_cast(steering_range))); + UpdateSteering(); + break; + + case CID_STEERING_R: + data.steering_right = static_cast(std::lroundf(value * static_cast(steering_range))); + UpdateSteering(); + break; + + case CID_THROTTLE: + data.throttle = static_cast(255 - std::clamp(std::lroundf(value * 255.0f), 0, 255)); + break; + + case CID_BRAKE: + data.brake = static_cast(255 - std::clamp(std::lroundf(value * 255.0f), 0, 255)); + break; + + case CID_DPAD_UP: + data.hat_up = static_cast(std::clamp(std::lroundf(value * 255.0f), 0, 255)); + UpdateHatSwitch(); + break; + case CID_DPAD_DOWN: + data.hat_down = static_cast(std::clamp(std::lroundf(value * 255.0f), 0, 255)); + UpdateHatSwitch(); + break; + case CID_DPAD_LEFT: + data.hat_left = static_cast(std::clamp(std::lroundf(value * 255.0f), 0, 255)); + UpdateHatSwitch(); + break; + case CID_DPAD_RIGHT: + data.hat_right = static_cast(std::clamp(std::lroundf(value * 255.0f), 0, 255)); + UpdateHatSwitch(); + break; + + case CID_BUTTON0: + case CID_BUTTON1: + case CID_BUTTON2: + case CID_BUTTON3: + case CID_BUTTON5: + case CID_BUTTON4: + case CID_BUTTON7: + case CID_BUTTON6: + case CID_BUTTON8: + case CID_BUTTON9: + case CID_BUTTON10: + case CID_BUTTON11: + case CID_BUTTON12: + case CID_BUTTON13: + case CID_BUTTON14: + case CID_BUTTON15: + case CID_BUTTON16: + case CID_BUTTON17: + case CID_BUTTON18: + case CID_BUTTON19: + case CID_BUTTON20: + case CID_BUTTON21: + case CID_BUTTON22: + { + const u32 mask = (1u << (bind_index - CID_BUTTON0)); + if (value >= 0.5f) + data.buttons |= mask; + else + data.buttons &= ~mask; + } + break; + + default: + break; + } + } + + void PadState::UpdateSteering() + { + u16 value; + if (data.steering_left > 0) + value = static_cast(std::max(steering_range - data.steering_left, 0)); + else + value = static_cast(std::min(steering_range + data.steering_right, steering_range * 2)); + + // TODO: Smoothing, don't jump too much + //data.steering = value; + if (value < data.steering) + data.steering -= std::min(data.steering - value, steering_step); + else if (value > data.steering) + data.steering += std::min(value - data.steering, steering_step); + } + + void PadState::UpdateHatSwitch() + { + if (data.hat_up && data.hat_right) + data.hatswitch = 1; + else if (data.hat_right && data.hat_down) + data.hatswitch = 3; + else if (data.hat_down && data.hat_left) + data.hatswitch = 5; + else if (data.hat_left && data.hat_up) + data.hatswitch = 7; + else if (data.hat_up) + data.hatswitch = 0; + else if (data.hat_right) + data.hatswitch = 2; + else if (data.hat_down) + data.hatswitch = 4; + else if (data.hat_left) + data.hatswitch = 6; + else + data.hatswitch = 8; + } + + bool PadState::HasFF() const + { + // only do force feedback for wheels... + return (type <= WT_GT_FORCE); + } + + void PadState::OpenFFDevice() + { + if (mFFdevName.empty()) + return; + + mFFdev.reset(); + +#ifdef SDL_BUILD + mFFdev = SDLFFDevice::Create(mFFdevName); +#endif + } + + static u32 gametrak_compute_key(u32* key) + { + u32 ret = 0; ret = *key << 2 & 0xFC0000; ret |= *key << 17 & 0x020000; ret ^= *key << 16 & 0xFE0000; @@ -164,70 +582,11 @@ namespace usb_pad ret |= *key << 7 & 0x008080; *key = ret; return ret >> 16; - }; - - typedef struct PADState - { - USBDevice dev; - USBDesc desc; - USBDescDevice desc_dev; - Pad* pad; - uint8_t port; - struct freeze - { - int dev_subtype; - } f; - uint8_t gametrak_state; - uint32_t gametrak_key; - uint8_t realplay_state; - } PADState; - - typedef struct u_wheel_data_t - { - union - { - generic_data_t generic_data; - dfp_data_t dfp_data; - gtforce_data_t gtf_data; - rb1drumkit_t rb1dk_data; - } u; - } u_wheel_data_t; - - //Convert DF Pro buttons to selected wheel type - uint32_t convert_wt_btn(PS2WheelTypes type, uint32_t inBtn) - { - if (type == WT_GT_FORCE) - { - /*** - R1 > SQUARE == menu down L1 > CROSS == menu up - SQUARE > CIRCLE == X TRIANG > TRIANG == Y - CROSS > R1 == A CIRCLE > L1 == B - ***/ - switch (inBtn) - { - case PAD_L1: - return PAD_CROSS; - case PAD_R1: - return PAD_SQUARE; - case PAD_SQUARE: - return PAD_CIRCLE; - case PAD_TRIANGLE: - return PAD_TRIANGLE; - case PAD_CIRCLE: - return PAD_L1; - case PAD_CROSS: - return PAD_R1; - default: - return PAD_BUTTON_COUNT; //Aka invalid - } - } - - return inBtn; } static void pad_handle_data(USBDevice* dev, USBPacket* p) { - PADState* s = (PADState*)dev; + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); uint8_t data[64]; int ret = 0; @@ -236,43 +595,12 @@ namespace usb_pad switch (p->pid) { case USB_TOKEN_IN: - if (devep == 1 && s->pad) + if (devep == 1) { - if (s->pad->Type() == WT_GAMETRAK_CONTROLLER) - { - if (s->gametrak_state == 0) - { - s->gametrak_state = 1; - const unsigned char secret[] = "Gametrak\0\0\0\0\0\0\0\0"; - memcpy(data, secret, sizeof(secret)); - usb_packet_copy(p, data, 16); - break; - } - else if (s->gametrak_state == 1) - { - s->pad->TokenIn(data, p->iov.size); - data[0x00] |= s->gametrak_key >> 16 & 1; - data[0x02] |= s->gametrak_key >> 17 & 1; - data[0x04] |= s->gametrak_key >> 18 & 1; - data[0x06] |= s->gametrak_key >> 19 & 1; - data[0x08] |= s->gametrak_key >> 20 & 1; - data[0x0A] |= s->gametrak_key >> 21 & 1; - usb_packet_copy(p, data, 16); - break; - } - } - else if (s->pad->Type() >= WT_REALPLAY_RACING && s->pad->Type() <= WT_REALPLAY_POOL) - { - s->pad->TokenIn(data, p->iov.size); - // simulate a slight move to avoid a game "protection" : controller disconnected - s->realplay_state = !s->realplay_state; - data[0] |= s->realplay_state; - usb_packet_copy(p, data, 19); - break; - } - ret = s->pad->TokenIn(data, p->iov.size); + ret = s->TokenIn(data, p->iov.size); + if (ret > 0) - usb_packet_copy(p, data, MIN(ret, (int)sizeof(data))); + usb_packet_copy(p, data, std::min(ret, (int)sizeof(data))); else p->status = ret; } @@ -282,11 +610,11 @@ namespace usb_pad } break; case USB_TOKEN_OUT: - usb_packet_copy(p, data, MIN(p->iov.size, sizeof(data))); + usb_packet_copy(p, data, std::min(p->iov.size, sizeof(data))); /*Console.Warning("usb-pad: data token out len=0x%X %X,%X,%X,%X,%X,%X,%X,%X\n",len, data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);*/ //Console.Warning("usb-pad: data token out len=0x%X\n",len); - ret = s->pad->TokenOut(data, p->iov.size); + ret = s->TokenOut(data, p->iov.size); break; default: fail: @@ -297,20 +625,16 @@ namespace usb_pad static void pad_handle_reset(USBDevice* dev) { - /* XXX: do it */ - PADState* s = (PADState*)dev; - s->pad->Reset(); - return; + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); + s->Reset(); } static void pad_handle_control(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + int index, int length, uint8_t* data) { - PADState* s = (PADState*)dev; + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); int ret = 0; - int t = s->pad->Type(); - switch (request) { case DeviceRequest | USB_REQ_GET_DESCRIPTOR: @@ -322,74 +646,42 @@ namespace usb_pad case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: //GT3 switch (value >> 8) { + // TODO: Move to constructor case USB_DT_REPORT: - if (t == WT_DRIVING_FORCE_PRO || t == WT_DRIVING_FORCE_PRO_1102) + if (s->type == WT_DRIVING_FORCE_PRO || s->type == WT_DRIVING_FORCE_PRO_1102) { ret = sizeof(pad_driving_force_pro_hid_report_descriptor); memcpy(data, pad_driving_force_pro_hid_report_descriptor, ret); } - else if (t == WT_GT_FORCE) + else if (s->type == WT_GT_FORCE) { ret = sizeof(pad_gtforce_hid_report_descriptor); memcpy(data, pad_gtforce_hid_report_descriptor, ret); } - else if (t == WT_KEYBOARDMANIA_CONTROLLER) + else if (s->type == WT_KEYBOARDMANIA_CONTROLLER) { ret = sizeof(kbm_hid_report_descriptor); memcpy(data, kbm_hid_report_descriptor, ret); } - else if (t == WT_GENERIC) + else if (s->type == WT_GENERIC) { ret = sizeof(pad_driving_force_hid_separate_report_descriptor); memcpy(data, pad_driving_force_hid_separate_report_descriptor, ret); } - else if (t == WT_BUZZ_CONTROLLER) + else if (s->type == WT_BUZZ_CONTROLLER) { ret = sizeof(buzz_hid_report_descriptor); memcpy(data, buzz_hid_report_descriptor, ret); } - else if (t == WT_GAMETRAK_CONTROLLER) - { - ret = sizeof(gametrak_hid_report_descriptor); - memcpy(data, gametrak_hid_report_descriptor, ret); - } - else if (t >= WT_REALPLAY_RACING && t <= WT_REALPLAY_POOL) - { - ret = sizeof(realplay_hid_report_descriptor); - memcpy(data, realplay_hid_report_descriptor, ret); - } p->actual_length = ret; break; default: goto fail; } break; + /* hid specific requests */ case SET_REPORT: - if (t == WT_GAMETRAK_CONTROLLER) - { - const char secret[] = "Gametrak"; - if (length == 8 && memcmp(data, secret, 8) == 0) - { - s->gametrak_state = 0; - s->gametrak_key = 0; - } - else if (length == 2) - { - if (data[0] == 0x45) - { - s->gametrak_key = data[1] << 16; - } - if ((s->gametrak_key >> 16) == data[1]) - { - gametrak_compute_key(&s->gametrak_key); - } - else - { - fprintf(stderr, "gametrak error : own key = %02x, recv key = %02x\n", s->gametrak_key >> 16, data[1]); - } - } - } // no idea, Rock Band 2 keeps spamming this if (length > 0) { @@ -418,324 +710,32 @@ namespace usb_pad static void pad_handle_destroy(USBDevice* dev) { - PADState* s = (PADState*)dev; + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); delete s; } - int pad_open(USBDevice* dev) + static void pad_init(PadState* s) { - PADState* s = (PADState*)dev; - if (s) - return s->pad->Open(); - return 1; - } - - void pad_close(USBDevice* dev) - { - PADState* s = (PADState*)dev; - if (s) - s->pad->Close(); - } - - void pad_reset_data(generic_data_t* d) - { - memset(d, 0, sizeof(generic_data_t)); - d->axis_x = 0x3FF >> 1; - d->axis_y = 0xFF; - d->axis_z = 0xFF; - d->axis_rz = 0xFF; - } - - void pad_reset_data(dfp_data_t* d) - { - memset(d, 0, sizeof(dfp_data_t)); - d->axis_x = 0x3FFF >> 1; - //d->axis_y = 0xFF; - d->axis_z = 0x3F; - d->axis_rz = 0x3F; - } - - void pad_copy_data(PS2WheelTypes type, uint8_t* buf, wheel_data_t& data) - { -#if 1 - struct wheel_data_t - { - uint32_t lo; - uint32_t hi; - }; - - wheel_data_t* w = (wheel_data_t*)buf; - memset(w, 0, 8); - - switch (type) - { - case WT_GENERIC: - w->lo = data.steering & 0x3FF; - w->lo |= (data.buttons & 0xFFF) << 10; - w->lo |= 0xFF << 24; - - w->hi = (data.hatswitch & 0xF); - w->hi |= (data.throttle & 0xFF) << 8; - w->hi |= (data.brake & 0xFF) << 16; - - break; - - case WT_GT_FORCE: - - w->lo = data.steering & 0x3FF; - w->lo |= (data.buttons & 0xFFF) << 10; - w->lo |= 0xFF << 24; - - w->hi = (data.throttle & 0xFF); - w->hi |= (data.brake & 0xFF) << 8; - - break; - case WT_DRIVING_FORCE_PRO: - - w->lo = data.steering & 0x3FFF; - w->lo |= (data.buttons & 0x3FFF) << 14; - w->lo |= (data.hatswitch & 0xF) << 28; - - w->hi = 0x00; - w->hi |= data.throttle << 8; - w->hi |= data.brake << 16; //axis_rz - w->hi |= 0x11 << 24; //enables wheel and pedals? - - //PrintBits(w, sizeof(*w)); - - break; - case WT_DRIVING_FORCE_PRO_1102: - - // what's up with the bitmap? - // xxxxxxxx xxxxxxbb bbbbbbbb bbbbhhhh ???????? ?01zzzzz 1rrrrrr1 10001000 - w->lo = data.steering & 0x3FFF; - w->lo |= (data.buttons & 0x3FFF) << 14; - w->lo |= (data.hatswitch & 0xF) << 28; - - w->hi = 0x00; - //w->hi |= 0 << 9; //bit 9 must be 0 - w->hi |= (1 | (data.throttle * 0x3F) / 0xFF) << 10; //axis_z - w->hi |= 1 << 16; //bit 16 must be 1 - w->hi |= ((0x3F - (data.brake * 0x3F) / 0xFF) & 0x3F) << 17; //axis_rz - w->hi |= 1 << 23; //bit 23 must be 1 - w->hi |= 0x11 << 24; //enables wheel and pedals? - - //PrintBits(w, sizeof(*w)); - - break; - case WT_ROCKBAND1_DRUMKIT: - w->lo = (data.buttons & 0xFFF); - w->lo |= (data.hatswitch & 0xF) << 16; - break; - - case WT_BUZZ_CONTROLLER: - // https://gist.github.com/Lewiscowles1986/eef220dac6f0549e4702393a7b9351f6 - buf[0] = 0x7f; - buf[1] = 0x7f; - buf[2] = data.buttons & 0xff; - buf[3] = (data.buttons >> 8) & 0xff; - buf[4] = 0xf0 | ((data.buttons >> 16) & 0xf); - break; - - case WT_GAMETRAK_CONTROLLER: - memset(buf, 0, 16); - buf[0] = data.clutch & 0xfe; - buf[1] = data.clutch >> 8; - buf[2] = data.throttle & 0xfe; - buf[3] = data.throttle >> 8; - buf[4] = data.brake & 0xfe; - buf[5] = data.brake >> 8; - buf[6] = data.hatswitch & 0xfe; - buf[7] = data.hatswitch >> 8; - buf[8] = data.hat_horz & 0xfe; - buf[9] = data.hat_horz >> 8; - buf[10] = data.hat_vert & 0xfe; - buf[11] = data.hat_vert >> 8; - buf[12] = data.buttons; - break; - - case WT_REALPLAY_RACING: - case WT_REALPLAY_SPHERE: - case WT_REALPLAY_GOLF: - case WT_REALPLAY_POOL: - memset(buf, 0, 19); - buf[0] = data.clutch & 0xfe; - buf[1] = data.clutch >> 8; - buf[2] = data.throttle & 0xff; - buf[3] = data.throttle >> 8; - buf[4] = data.brake & 0xff; - buf[5] = data.brake >> 8; - buf[14] = data.buttons; - break; - - case WT_SEGA_SEAMIC: - buf[0] = data.steering & 0xFF; - buf[1] = data.throttle & 0xFF; - buf[2] = data.brake & 0xFF; - buf[3] = data.hatswitch & 0x0F; // 4bits? - buf[3] |= (data.buttons & 0x0F) << 4; // 4 bits // TODO Or does it start at buf[4]? - buf[4] = (data.buttons >> 4) & 0x3F; // 10 - 4 = 6 bits - break; - - case WT_KEYBOARDMANIA_CONTROLLER: - buf[0] = 0x3F; - buf[1] = data.buttons & 0xFF; - buf[2] = (data.buttons >> 8) & 0xFF; - buf[3] = (data.buttons >> 16) & 0xFF; - buf[4] = (data.buttons >> 24) & 0xFF; - break; - - default: - break; - } - -#else - - u_wheel_data_t* w = (u_wheel_data_t*)buf; - - //Console.Warning("usb-pad: axis x %d\n", data.axis_x); - switch (type) - { - case WT_GENERIC: - memset(&w->u.generic_data, 0xff, sizeof(generic_data_t)); - //pad_reset_data(&w->u.generic_data); - - w->u.generic_data.buttons = data.buttons; - w->u.generic_data.hatswitch = data.hatswitch; - w->u.generic_data.axis_x = data.steering; - w->u.generic_data.axis_y = 0xFF; //data.clutch; - w->u.generic_data.axis_z = data.throttle; - w->u.generic_data.axis_rz = data.brake; - - break; - - case WT_DRIVING_FORCE_PRO: - //memset(&w->u.dfp_data, 0, sizeof(dfp_data_t)); - //pad_reset_data(&w->u.dfp_data); - - w->u.dfp_data.buttons = data.buttons; - w->u.dfp_data.hatswitch = data.hatswitch; - w->u.dfp_data.axis_x = data.steering; - w->u.dfp_data.axis_z = data.throttle; - w->u.dfp_data.axis_rz = data.brake; - - w->u.dfp_data.magic1 = 1; - w->u.dfp_data.magic2 = 1; - w->u.dfp_data.magic3 = 1; - w->u.dfp_data.magic4 = - 1 << 0 | //enable pedals? - 0 << 1 | - 0 << 2 | - 0 << 3 | - 1 << 4 | //enable wheel? - 0 << 5 | - 0 << 6 | - 0 << 7; - - PrintBits(&w->u.dfp_data, sizeof(dfp_data_t)); - - break; - - case WT_DRIVING_FORCE_PRO_1102: - //memset(&w->u.dfp_data, 0, sizeof(dfp_data_t)); - //pad_reset_data(&w->u.dfp_data); - - w->u.dfp_data.buttons = data.buttons; - w->u.dfp_data.hatswitch = data.hatswitch; - w->u.dfp_data.axis_x = data.steering; - w->u.dfp_data.axis_z = 1 | (data.throttle * 0x3F) / 0xFF; //TODO Always > 0 or everything stops working, wut. - w->u.dfp_data.axis_rz = 0x3F - (data.brake * 0x3F) / 0xFF; - - w->u.dfp_data.magic1 = 1; - w->u.dfp_data.magic2 = 1; - w->u.dfp_data.magic3 = 1; - w->u.dfp_data.magic4 = - 1 << 0 | //enable pedals? - 0 << 1 | - 0 << 2 | - 0 << 3 | - 1 << 4 | //enable wheel? - 0 << 5 | - 0 << 6 | - 0 << 7; - - PrintBits(&w->u.dfp_data, sizeof(dfp_data_t)); - - break; - - case WT_GT_FORCE: - memset(&w->u.gtf_data, 0xff, sizeof(gtforce_data_t)); - - w->u.gtf_data.buttons = data.buttons; - w->u.gtf_data.axis_x = data.steering; - w->u.gtf_data.axis_y = 0xFF; //data.clutch; - w->u.gtf_data.axis_z = data.throttle; - w->u.gtf_data.axis_rz = data.brake; - - break; - - case WT_ROCKBAND1_DRUMKIT: - memset(&w->u.rb1dk_data, 0x0, sizeof(rb1drumkit_t)); - - w->u.rb1dk_data.u.buttons = data.buttons; - w->u.rb1dk_data.hatswitch = data.hatswitch; - - break; - - default: - break; - } - -#endif - } - - static void pad_init(PADState* s, int port, Pad* pad) - { - s->f.dev_subtype = pad->Type(); - s->pad = pad; - s->port = port; - s->dev.speed = USB_SPEED_FULL; s->dev.klass.handle_attach = usb_desc_attach; s->dev.klass.handle_reset = pad_handle_reset; s->dev.klass.handle_control = pad_handle_control; s->dev.klass.handle_data = pad_handle_data; s->dev.klass.unrealize = pad_handle_destroy; - s->dev.klass.open = pad_open; - s->dev.klass.close = pad_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = nullptr; usb_desc_init(&s->dev); usb_ep_init(&s->dev); - pad_handle_reset((USBDevice*)s); + pad_handle_reset(&s->dev); } - USBDevice* PadDevice::CreateDevice(int port) + USBDevice* PadDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("USB: PAD: Invalid input API.\n"); - return nullptr; - } - - Pad* pad = proxy->CreateObject(port, TypeName()); - - if (!pad) + if (subtype >= WT_COUNT) return nullptr; - pad->Type((PS2WheelTypes)GetSelectedSubtype(std::make_pair(port, TypeName()))); - PADState* s = new PADState(); - + PadState* s = new PadState(port, static_cast(subtype)); s->desc.full = &s->desc_dev; s->desc.str = df_desc_strings; @@ -744,7 +744,7 @@ namespace usb_pad const uint8_t* config_desc = df_config_descriptor; int config_desc_len = sizeof(df_config_descriptor); - switch (pad->Type()) + switch (s->type) { case WT_DRIVING_FORCE_PRO: { @@ -781,72 +781,99 @@ namespace usb_pad if (usb_desc_parse_config(config_desc, config_desc_len, s->desc_dev) < 0) goto fail; - pad_init(s, port, pad); + s->UpdateSettings(si, TypeName()); + pad_init(s); - return (USBDevice*)s; + return &s->dev; fail: - pad_handle_destroy((USBDevice*)s); + pad_handle_destroy(&s->dev); return nullptr; } - int PadDevice::Configure(int port, const std::string& api, void* data) + const char* PadDevice::Name() const { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; + return "Wheel Device"; } - int PadDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* PadDevice::TypeName() const { - PADState* s = (PADState*)dev; + return "Pad"; + } - if (!s) - return 0; - switch (mode) - { - case FreezeAction::Load: - s->f = *(PADState::freeze*)data; - s->pad->Type((PS2WheelTypes)s->f.dev_subtype); - return sizeof(PADState::freeze); - case FreezeAction::Save: - *(PADState::freeze*)data = s->f; - return sizeof(PADState::freeze); - case FreezeAction::Size: - return sizeof(PADState::freeze); - default: - break; - } - return 0; + bool PadDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); + + if (!sw.DoMarker("PadDevice")) + return false; + + sw.Do(&s->data.last_steering); + sw.DoPOD(&s->mFFstate); + return true; + } + + void PadDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const + { + USB_CONTAINER_OF(dev, PadState, dev)->UpdateSettings(si, TypeName()); + } + + float PadDevice::GetBindingValue(const USBDevice* dev, u32 bind_index) const + { + const PadState* s = USB_CONTAINER_OF(dev, const PadState, dev); + return s->GetBindValue(bind_index); + } + + void PadDevice::SetBindingValue(USBDevice* dev, u32 bind_index, float value) const + { + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); + s->SetBindValue(bind_index, value); + } + + std::vector PadDevice::SubTypes() const + { + return {"Driving Force", "Driving Force Pro", "Driving Force Pro (rev11.02)", "GT Force"}; + } + + gsl::span PadDevice::Bindings(u32 subtype) const + { + return GetWheelBindings(static_cast(subtype)); + } + + gsl::span PadDevice::Settings(u32 subtype) const + { + return GetWheelSettings(static_cast(subtype)); + } + + void PadDevice::InputDeviceConnected(USBDevice* dev, const std::string_view& identifier) const + { + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); + if (s->mFFdevName == identifier) + s->OpenFFDevice(); + } + + void PadDevice::InputDeviceDisconnected(USBDevice* dev, const std::string_view& identifier) const + { + PadState* s = USB_CONTAINER_OF(dev, PadState, dev); + if (s->mFFdevName == identifier) + s->mFFdev.reset(); } // ---- Rock Band drum kit ---- - USBDevice* RBDrumKitDevice::CreateDevice(int port) + const char* RBDrumKitDevice::Name() const { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("RBDK: Invalid input API.\n"); - return nullptr; - } + return "Rock Band Drum Kit"; + } - Pad* pad = proxy->CreateObject(port, TypeName()); + const char* RBDrumKitDevice::TypeName() const + { + return "RBDrumKit"; + } - if (!pad) - return nullptr; - - pad->Type(WT_ROCKBAND1_DRUMKIT); - PADState* s = new PADState(); + USBDevice* RBDrumKitDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + PadState* s = new PadState(port, WT_ROCKBAND1_DRUMKIT); s->desc.full = &s->desc_dev; s->desc.str = rb1_desc_strings; @@ -856,54 +883,78 @@ namespace usb_pad if (usb_desc_parse_config(rb1_config_descriptor, sizeof(rb1_config_descriptor), s->desc_dev) < 0) goto fail; - pad_init(s, port, pad); + pad_init(s); - return (USBDevice*)s; + return &s->dev; fail: - pad_handle_destroy((USBDevice*)s); + pad_handle_destroy(&s->dev); return nullptr; } - int RBDrumKitDevice::Configure(int port, const std::string& api, void* data) + std::vector RBDrumKitDevice::SubTypes() const { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; + return {}; } - int RBDrumKitDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + gsl::span RBDrumKitDevice::Bindings(u32 subtype) const { - return PadDevice::Freeze(mode, dev, data); + static constexpr const InputBindingInfo bindings[] = { + {"Blue", "Blue", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::R1}, + {"Green", "Green", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Triangle}, + {"Red", "Red", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Circle}, + {"Yellow", "Yellow", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Square}, + {"Orange", "Orange", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::Cross}, + {"Select", "Select", InputBindingInfo::Type::Button, CID_BUTTON8, GenericInputBinding::Select}, + {"Start", "Start", InputBindingInfo::Type::Button, CID_BUTTON9, GenericInputBinding::Start}, + }; + + return bindings; + } + + gsl::span RBDrumKitDevice::Settings(u32 subtype) const + { + return {}; } // ---- Buzz ---- - USBDevice* BuzzDevice::CreateDevice(int port) + const char* BuzzDevice::Name() const { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("Buzz: Invalid input API.\n"); - return nullptr; - } + return "Buzz Controller"; + } - Pad* pad = proxy->CreateObject(port, TypeName()); + const char* BuzzDevice::TypeName() const + { + return "BuzzDevice"; + } - if (!pad) - return nullptr; + std::vector BuzzDevice::SubTypes() const + { + return {}; + } - pad->Type(WT_BUZZ_CONTROLLER); - PADState* s = new PADState(); + gsl::span BuzzDevice::Bindings(u32 subtype) const + { + static constexpr const InputBindingInfo bindings[] = { + {"Red", "Red", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::R1}, + {"Yellow", "Yellow", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Triangle}, + {"Green", "Green", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Circle}, + {"Orange", "Orange", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Square}, + {"Blue", "Blue", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::Cross}, + }; + + return bindings; + } + + gsl::span BuzzDevice::Settings(u32 subtype) const + { + return {}; + } + + USBDevice* BuzzDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + PadState* s = new PadState(port, WT_BUZZ_CONTROLLER); s->desc.full = &s->desc_dev; s->desc.str = buzz_desc_strings; @@ -913,54 +964,73 @@ namespace usb_pad if (usb_desc_parse_config(buzz_config_descriptor, sizeof(buzz_config_descriptor), s->desc_dev) < 0) goto fail; - pad_init(s, port, pad); + pad_init(s); - return (USBDevice*)s; + return &s->dev; fail: - pad_handle_destroy((USBDevice*)s); + pad_handle_destroy(&s->dev); return nullptr; } - int BuzzDevice::Configure(int port, const std::string& api, void* data) - { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; - } - - int BuzzDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) - { - return PadDevice::Freeze(mode, dev, data); - } - // ---- Keyboardmania ---- - USBDevice* KeyboardmaniaDevice::CreateDevice(int port) + const char* KeyboardmaniaDevice::Name() const { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("usb-pad: %s: Invalid input API.", TypeName()); - return nullptr; - } + return "Keyboardmania"; + } - Pad* pad = proxy->CreateObject(port, TypeName()); + const char* KeyboardmaniaDevice::TypeName() const + { + return "Keyboardmania"; + } - if (!pad) - return nullptr; + std::vector KeyboardmaniaDevice::SubTypes() const + { + return {}; + } - pad->Type(WT_KEYBOARDMANIA_CONTROLLER); - PADState* s = new PADState(); + gsl::span KeyboardmaniaDevice::Bindings(u32 subtype) const + { + static constexpr const InputBindingInfo bindings[] = { + {"C", "C", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::Unknown}, + {"CSharp", "C#", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Unknown}, + {"D", "D", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Unknown}, + {"EFlat", "Eb", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Unknown}, + {"E", "E", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::Unknown}, + {"F", "F", InputBindingInfo::Type::Button, CID_BUTTON5, GenericInputBinding::Unknown}, + {"FSharp", "F#", InputBindingInfo::Type::Button, CID_BUTTON6, GenericInputBinding::Unknown}, + {"G", "G", InputBindingInfo::Type::Button, CID_BUTTON7, GenericInputBinding::Unknown}, + {"AFlat", "Ab", InputBindingInfo::Type::Button, CID_BUTTON8, GenericInputBinding::Unknown}, + {"A", "A", InputBindingInfo::Type::Button, CID_BUTTON9, GenericInputBinding::Unknown}, + {"BFlat", "Bb", InputBindingInfo::Type::Button, CID_BUTTON10, GenericInputBinding::Unknown}, + {"B", "B", InputBindingInfo::Type::Button, CID_BUTTON11, GenericInputBinding::Unknown}, + {"C2", "+C", InputBindingInfo::Type::Button, CID_BUTTON12, GenericInputBinding::Unknown}, + {"CSharp2", "+C#", InputBindingInfo::Type::Button, CID_BUTTON13, GenericInputBinding::Unknown}, + {"D2", "+D", InputBindingInfo::Type::Button, CID_BUTTON14, GenericInputBinding::Unknown}, + {"EFlat2", "+Eb", InputBindingInfo::Type::Button, CID_BUTTON15, GenericInputBinding::Unknown}, + {"E2", "+E", InputBindingInfo::Type::Button, CID_BUTTON16, GenericInputBinding::Unknown}, + {"F2", "+F", InputBindingInfo::Type::Button, CID_BUTTON17, GenericInputBinding::Unknown}, + {"FSharp2", "+F#", InputBindingInfo::Type::Button, CID_BUTTON18, GenericInputBinding::Unknown}, + {"G2", "+G", InputBindingInfo::Type::Button, CID_BUTTON19, GenericInputBinding::Unknown}, + {"AFlat2", "+Ab", InputBindingInfo::Type::Button, CID_BUTTON20, GenericInputBinding::Unknown}, + {"A2", "+A", InputBindingInfo::Type::Button, CID_BUTTON21, GenericInputBinding::Unknown}, + {"BFlat2", "+Bb", InputBindingInfo::Type::Button, CID_BUTTON22, GenericInputBinding::Unknown}, + {"B2", "+B", InputBindingInfo::Type::Button, CID_BUTTON23, GenericInputBinding::Unknown}, + {"C3", "++C", InputBindingInfo::Type::Button, CID_BUTTON24, GenericInputBinding::Unknown}, + }; + + return bindings; + } + + gsl::span KeyboardmaniaDevice::Settings(u32 subtype) const + { + return {}; + } + + USBDevice* KeyboardmaniaDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + PadState* s = new PadState(port, WT_KEYBOARDMANIA_CONTROLLER); s->desc.full = &s->desc_dev; s->desc.str = kbm_desc_strings; @@ -970,178 +1040,12 @@ namespace usb_pad if (usb_desc_parse_config(kbm_config_descriptor, sizeof(kbm_config_descriptor), s->desc_dev) < 0) goto fail; - pad_init(s, port, pad); + pad_init(s); - return (USBDevice*)s; + return &s->dev; fail: - pad_handle_destroy((USBDevice*)s); + pad_handle_destroy(&s->dev); return nullptr; } - - int KeyboardmaniaDevice::Configure(int port, const std::string& api, void* data) - { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; - } - - int KeyboardmaniaDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) - { - return PadDevice::Freeze(mode, dev, data); - } - - // ---- Gametrak ---- - - USBDevice* GametrakDevice::CreateDevice(int port) - { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("Gametrak: Invalid input API."); - return nullptr; - } - - Pad* pad = proxy->CreateObject(port, TypeName()); - - if (!pad) - return nullptr; - - pad->Type(WT_GAMETRAK_CONTROLLER); - PADState* s = new PADState(); - - s->desc.full = &s->desc_dev; - s->desc.str = gametrak_desc_strings; - - if (usb_desc_parse_dev(gametrak_dev_descriptor, sizeof(gametrak_dev_descriptor), s->desc, s->desc_dev) < 0) - goto fail; - if (usb_desc_parse_config(gametrak_config_descriptor, sizeof(gametrak_config_descriptor), s->desc_dev) < 0) - goto fail; - - s->f.dev_subtype = pad->Type(); - s->pad = pad; - s->port = port; - s->dev.speed = USB_SPEED_FULL; - s->dev.klass.handle_attach = usb_desc_attach; - s->dev.klass.handle_reset = pad_handle_reset; - s->dev.klass.handle_control = pad_handle_control; - s->dev.klass.handle_data = pad_handle_data; - s->dev.klass.unrealize = pad_handle_destroy; - s->dev.klass.open = pad_open; - s->dev.klass.close = pad_close; - s->dev.klass.usb_desc = &s->desc; - s->dev.klass.product_desc = s->desc.str[2]; - - usb_desc_init(&s->dev); - usb_ep_init(&s->dev); - pad_handle_reset((USBDevice*)s); - - return (USBDevice*)s; - - fail: - pad_handle_destroy((USBDevice*)s); - return nullptr; - } - - int GametrakDevice::Configure(int port, const std::string& api, void* data) - { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; - } - - int GametrakDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) - { - return PadDevice::Freeze(mode, dev, data); - } - - // ---- RealPlay ---- - - USBDevice* RealPlayDevice::CreateDevice(int port) - { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("RealPlay: Invalid input API"); - return nullptr; - } - - Pad* pad = proxy->CreateObject(port, TypeName()); - - if (!pad) - return nullptr; - - pad->Type((PS2WheelTypes)(WT_REALPLAY_RACING + GetSelectedSubtype(std::make_pair(port, TypeName())))); - PADState* s = new PADState(); - - s->desc.full = &s->desc_dev; - s->desc.str = realplay_desc_strings; - - if (pad->Type() == WT_REALPLAY_RACING && usb_desc_parse_dev(realplay_racing_dev_descriptor, sizeof(realplay_racing_dev_descriptor), s->desc, s->desc_dev) < 0) - goto fail; - if (pad->Type() == WT_REALPLAY_SPHERE && usb_desc_parse_dev(realplay_sphere_dev_descriptor, sizeof(realplay_sphere_dev_descriptor), s->desc, s->desc_dev) < 0) - goto fail; - if (pad->Type() == WT_REALPLAY_GOLF && usb_desc_parse_dev(realplay_golf_dev_descriptor, sizeof(realplay_golf_dev_descriptor), s->desc, s->desc_dev) < 0) - goto fail; - if (pad->Type() == WT_REALPLAY_POOL && usb_desc_parse_dev(realplay_pool_dev_descriptor, sizeof(realplay_pool_dev_descriptor), s->desc, s->desc_dev) < 0) - goto fail; - if (usb_desc_parse_config(realplay_config_descriptor, sizeof(realplay_config_descriptor), s->desc_dev) < 0) - goto fail; - - s->f.dev_subtype = pad->Type(); - s->pad = pad; - s->port = port; - s->dev.speed = USB_SPEED_FULL; - s->dev.klass.handle_attach = usb_desc_attach; - s->dev.klass.handle_reset = pad_handle_reset; - s->dev.klass.handle_control = pad_handle_control; - s->dev.klass.handle_data = pad_handle_data; - s->dev.klass.unrealize = pad_handle_destroy; - s->dev.klass.open = pad_open; - s->dev.klass.close = pad_close; - s->dev.klass.usb_desc = &s->desc; - s->dev.klass.product_desc = s->desc.str[1]; - - usb_desc_init(&s->dev); - usb_ep_init(&s->dev); - pad_handle_reset((USBDevice*)s); - - return (USBDevice*)s; - - fail: - pad_handle_destroy((USBDevice*)s); - return nullptr; - } - - int RealPlayDevice::Configure(int port, const std::string& api, void* data) - { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; - } - - int RealPlayDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) - { - return PadDevice::Freeze(mode, dev, data); - } - } // namespace usb_pad diff --git a/pcsx2/USB/usb-pad/usb-pad.h b/pcsx2/USB/usb-pad/usb-pad.h index 10153060e7..befefef65b 100644 --- a/pcsx2/USB/usb-pad/usb-pad.h +++ b/pcsx2/USB/usb-pad/usb-pad.h @@ -13,196 +13,125 @@ * If not, see . */ -#ifndef USBPAD_H -#define USBPAD_H +#pragma once -#include "USB/qemu-usb/vl.h" -#include "USB/configuration.h" +#include "USB/qemu-usb/qusb.h" +#include "USB/qemu-usb/desc.h" #include "USB/deviceproxy.h" namespace usb_pad { - -#define CHECK(exp) \ - do \ - { \ - if (!(exp)) \ - goto Error; \ - } while (0) -#define SAFE_FREE(p) \ - do \ - { \ - if (p) \ - { \ - free(p); \ - (p) = NULL; \ - } \ - } while (0) - -#define S_CONFIG_JOY TEXT("Joystick") -#define N_JOYSTICK TEXT("joystick") - - class PadDevice + enum ControlID { - public: - virtual ~PadDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Wheel device"); - } - static const char* TypeName() - { - return "pad"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {"Driving Force", "Driving Force Pro", "Driving Force Pro (rev11.02)", "GT Force"}; - } + CID_STEERING_L, + CID_STEERING_R, + CID_THROTTLE, + CID_BRAKE, + CID_DPAD_UP, + CID_DPAD_DOWN, + CID_DPAD_LEFT, + CID_DPAD_RIGHT, + CID_BUTTON0, // cross + CID_BUTTON1, // square + CID_BUTTON2, // circle + CID_BUTTON3, // triangle + CID_BUTTON4, // R1 + CID_BUTTON5, // L1 + CID_BUTTON6, // R2 + CID_BUTTON7, // L2 + CID_BUTTON8, // select + CID_BUTTON9, // start + CID_BUTTON10, // R3 + CID_BUTTON11, // L3 + CID_BUTTON12, + CID_BUTTON13, + CID_BUTTON14, + CID_BUTTON15, + CID_BUTTON16, + CID_BUTTON17, + CID_BUTTON18, + CID_BUTTON19, + CID_BUTTON20, + CID_BUTTON21, + CID_BUTTON22, + CID_BUTTON23, + CID_BUTTON24, + CID_COUNT, }; - class RBDrumKitDevice + enum PS2WheelTypes { - public: - virtual ~RBDrumKitDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Rock Band drum kit"); - } - static const char* TypeName() - { - return "rbdrumkit"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + WT_GENERIC, // DF or any other LT wheel in non-native mode + WT_DRIVING_FORCE_PRO, //LPRC-11000? DF GT can be downgraded to Pro (?) + WT_DRIVING_FORCE_PRO_1102, //hw with buggy hid report? + WT_GT_FORCE, //formula gp + WT_ROCKBAND1_DRUMKIT, + WT_BUZZ_CONTROLLER, + WT_SEGA_SEAMIC, + WT_KEYBOARDMANIA_CONTROLLER, + WT_COUNT, }; - class BuzzDevice + class PadDevice : public DeviceProxy { public: - virtual ~BuzzDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Buzz Device"); - } - static const char* TypeName() - { - return "buzz_device"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* Name() const override; + const char* TypeName() const override; + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override; + float GetBindingValue(const USBDevice* dev, u32 bind_index) const override; + void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override; + void InputDeviceConnected(USBDevice* dev, const std::string_view& identifier) const override; + void InputDeviceDisconnected(USBDevice* dev, const std::string_view& identifier) const override; + std::vector SubTypes() const override; + gsl::span Bindings(u32 subtype) const override; + gsl::span Settings(u32 subtype) const override; }; - class GametrakDevice + class RBDrumKitDevice final : public PadDevice { public: - virtual ~GametrakDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Gametrak Device"); - } - static const char* TypeName() - { - return "gametrak_device"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return std::vector(); - } - static void Initialize(); + const char* Name() const override; + const char* TypeName() const override; + std::vector SubTypes() const override; + gsl::span Bindings(u32 subtype) const override; + gsl::span Settings(u32 subtype) const override; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; }; - class RealPlayDevice + class BuzzDevice final : public PadDevice { public: - virtual ~RealPlayDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("RealPlay Device"); - } - static const char* TypeName() - { - return "realplay_device"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {"RealPlay Racing", "RealPlay Sphere", "RealPlay Golf", "RealPlay Pool"}; - } - static void Initialize(); + const char* Name() const; + const char* TypeName() const; + std::vector SubTypes() const; + gsl::span Bindings(u32 subtype) const; + gsl::span Settings(u32 subtype) const; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const; }; - class SeamicDevice + class SeamicDevice final : public PadDevice { public: - virtual ~SeamicDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Sega Seamic"); - } - static const char* TypeName() - { - return "seamic"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + const char* Name() const; + const char* TypeName() const; + std::vector SubTypes() const; + gsl::span Bindings(u32 subtype) const; + gsl::span Settings(u32 subtype) const; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const; + bool Freeze(USBDevice* dev, StateWrapper& sw) const; }; - class KeyboardmaniaDevice + class KeyboardmaniaDevice final : public PadDevice { public: - virtual ~KeyboardmaniaDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Keyboardmania"); - } - static const char* TypeName() - { - return "keyboardmania"; - } - static std::list ListAPIs(); - static const TCHAR* LongAPIName(const std::string& name); - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - return {}; - } + const char* Name() const; + const char* TypeName() const; + std::vector SubTypes() const; + gsl::span Bindings(u32 subtype) const; + gsl::span Settings(u32 subtype) const; + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const; }; // Most likely as seen on https://github.com/matlo/GIMX @@ -245,45 +174,7 @@ namespace usb_pad #define FTYPE_HIGH_RESOLUTION_AUTO_CENTER_SPRING 0x0D #define FTYPE_FRICTION 0x0E - enum PS2WheelTypes - { - WT_GENERIC, // DF or any other LT wheel in non-native mode - WT_DRIVING_FORCE_PRO, //LPRC-11000? DF GT can be downgraded to Pro (?) - WT_DRIVING_FORCE_PRO_1102, //hw with buggy hid report? - WT_GT_FORCE, //formula gp - WT_ROCKBAND1_DRUMKIT, - WT_BUZZ_CONTROLLER, - WT_GAMETRAK_CONTROLLER, - WT_REALPLAY_RACING, - WT_REALPLAY_SPHERE, - WT_REALPLAY_GOLF, - WT_REALPLAY_POOL, - WT_SEGA_SEAMIC, - WT_KEYBOARDMANIA_CONTROLLER, - }; - inline int range_max(PS2WheelTypes type) - { - if (type == WT_DRIVING_FORCE_PRO || type == WT_DRIVING_FORCE_PRO_1102) - return 0x3FFF; - if (type == WT_SEGA_SEAMIC) - return 255; - return 0x3FF; - } - - // hold intermediate wheel data - struct wheel_data_t - { - int32_t steering; - uint32_t buttons; - uint32_t hatswitch; - uint32_t hat_horz; - uint32_t hat_vert; - - int32_t clutch; //no game uses though - int32_t throttle; - int32_t brake; - }; struct spring { @@ -415,117 +306,61 @@ namespace usb_pad virtual void DisableForce(EffectID force) = 0; }; - class Pad + struct PadState { - public: - Pad(int port, const char* dev_type) - : mPort(port) - , mDevType(dev_type) - { - memset(&mFFstate, 0, sizeof(mFFstate)); - } - virtual ~Pad() - { - delete mFFdev; - mFFdev = nullptr; - } - virtual int Open() = 0; - virtual int Close() = 0; - virtual int TokenIn(uint8_t* buf, int len) = 0; - virtual int TokenOut(const uint8_t* data, int len) = 0; - virtual int Reset() = 0; + PadState(u32 port_, PS2WheelTypes type_); + ~PadState(); - virtual PS2WheelTypes Type() { return mType; } - virtual void Type(PS2WheelTypes type) { mType = type; } - virtual int Port() { return mPort; } - virtual void Port(int port) { mPort = port; } + void UpdateSettings(SettingsInterface& si, const char* devname); + + float GetBindValue(u32 bind) const; + void SetBindValue(u32 bind, float value); + + void Reset(); + int TokenIn(u8* buf, int len); + int TokenOut(const u8* buf, int len); + + void UpdateSteering(); + void UpdateHatSwitch(); + + bool HasFF() const; + void OpenFFDevice(); void ParseFFData(const ff_data* ffdata, bool isDFP); - protected: - PS2WheelTypes mType = PS2WheelTypes::WT_GENERIC; - wheel_data_t mWheelData{}; - ff_state mFFstate; - FFDevice* mFFdev = nullptr; - int mPort; - const char* mDevType; + USBDevice dev{}; + USBDesc desc{}; + USBDescDevice desc_dev{}; + + u32 port = 0; + PS2WheelTypes type = WT_GENERIC; + + s16 steering_range = 0; + u16 steering_step = 0; + + struct + { + // intermediate state, resolved at query time + s16 steering_left; + s16 steering_right; + bool hat_left : 1; + bool hat_right : 1; + bool hat_up : 1; + bool hat_down : 1; + + u8 hatswitch; // direction + u16 steering; // 0..steering_range*2 + u16 last_steering; + u32 buttons; // active high + + u8 throttle; // inverted, 0 = fully depressed + u8 brake; // inverted, 0 = fully depressed + } data = {}; + + std::string mFFdevName; + std::unique_ptr mFFdev; + ff_state mFFstate{}; }; - //L3/R3 for newer wheels - //enum PS2Buttons : uint32_t { - // PAD_CROSS = 0, PAD_SQUARE, PAD_CIRCLE, PAD_TRIANGLE, - // PAD_L1, PAD_L2, PAD_R1, PAD_R2, - // PAD_SELECT, PAD_START, - // PAD_L3, PAD_R3, //order - // PAD_BUTTON_COUNT - //}; - - //??? - //enum DFButtons : uint32_t { - // PAD_CROSS = 0, PAD_SQUARE, PAD_CIRCLE, PAD_TRIANGLE, - // PAD_R2, - // PAD_L2, - // PAD_R1, - // PAD_L1, - // PAD_SELECT, PAD_START, - // PAD_BUTTON_COUNT - //}; - - //DF Pro buttons (?) - //Based on Tokyo Xtreme Racer Drift 2 - //GT4 flips R1/L1 with R2/L2 with DF wheel type - enum PS2Buttons : uint32_t - { - PAD_CROSS = 0, //menu up - GT Force - PAD_SQUARE, //menu down - PAD_CIRCLE, //X - PAD_TRIANGLE, //Y - PAD_R1, //A? in GT4 - PAD_L1, //B - PAD_R2, - PAD_L2, - PAD_SELECT, - PAD_START, - PAD_R3, - PAD_L3, //order, only GT Force/Force EX? - PAD_SHIFT_UP, - PAD_SHIFT_DOWN, // DF Pro - PAD_BUTTON_COUNT - }; - - enum PS2Axis : uint32_t - { - PAD_AXIS_X, - PAD_AXIS_Y, - PAD_AXIS_Z, - PAD_AXIS_RZ, - PAD_AXIS_HAT, //Treat as axis for mapping purposes - PAD_AXIS_COUNT - }; - - enum PS2HatSwitch - { - PAD_HAT_N = 0, - PAD_HAT_NE, - PAD_HAT_E, - PAD_HAT_SE, - PAD_HAT_S, - PAD_HAT_SW, - PAD_HAT_W, - PAD_HAT_NW, - PAD_HAT_COUNT - }; - - enum Buzz - { - BUZZ_RED, - BUZZ_YELLOW, - BUZZ_GREEN, - BUZZ_ORANGE, - BUZZ_BLUE, - }; - - static const int HATS_8TO4[] = {PAD_HAT_N, PAD_HAT_E, PAD_HAT_S, PAD_HAT_W}; - #define PAD_VID 0x046D #define PAD_MOMO 0xCA03 //black MOMO #define GENERIC_PID 0xC294 //actually Driving Force aka PID that most logitech wheels initially report @@ -1507,464 +1342,4 @@ namespace usb_pad 0x81, 0x01, // INPUT (Constant,Array,Absolute) 0xc0 // END_COLLECTION }; - - ////////////// - // GameTrak // - ////////////// - - // Product ID : - // 0x0982 - PlayStation 2 - // 0x0984 - ??? - - [[maybe_unused]] static uint8_t gametrak_dev_descriptor[] = { - 0x12, // bLength - 0x01, // bDescriptorType (Device) - 0x10, 0x01, // bcdUSB 1.10 - 0x00, // bDeviceClass (Use class information in the Interface Descriptors) - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - 0x08, // bMaxPacketSize0 8 - 0xB7, 0x14, // idVendor 0x14B7 - 0x82, 0x09, // idProduct 0x0982 - 0x01, 0x00, // bcdDevice 0.01 - 0x01, // iManufacturer (String Index) - 0x02, // iProduct (String Index) - 0x00, // iSerialNumber (String Index) - 0x01, // bNumConfigurations 1 - }; - - static const uint8_t gametrak_config_descriptor[] = { - 0x09, // bLength - 0x02, // bDescriptorType (Configuration) - 0x22, 0x00, // wTotalLength 34 - 0x01, // bNumInterfaces 1 - 0x01, // bConfigurationValue - 0x00, // iConfiguration (String Index) - 0x80, // bmAttributes - 0x0A, // bMaxPower 20mA - - 0x09, // bLength - 0x04, // bDescriptorType (Interface) - 0x00, // bInterfaceNumber 0 - 0x00, // bAlternateSetting - 0x01, // bNumEndpoints 1 - 0x03, // bInterfaceClass - 0x00, // bInterfaceSubClass - 0x00, // bInterfaceProtocol - 0x00, // iInterface (String Index) - - 0x09, // bLength - 0x21, // bDescriptorType (HID) - 0x01, 0x01, // bcdHID 1.01 - 0x00, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) - 0x7A, 0x00, // wDescriptorLength[0] 122 - - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x81, // bEndpointAddress (IN/D2H) - 0x03, // bmAttributes (Interrupt) - 0x10, 0x00, // wMaxPacketSize 16 - 0x0A, // bInterval 10 (unit depends on device speed) - }; - - static const uint8_t gametrak_hid_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - 0xA1, 0x01, // Collection (Application) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Physical) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x33, // Usage (Rx) - 0x09, 0x34, // Usage (Ry) - 0x09, 0x35, // Usage (Rz) - 0x16, 0x00, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x0F, // Logical Maximum (4095) - 0x36, 0x00, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x0F, // Physical Maximum (4095) - 0x66, 0x00, 0x00, // Unit (None) - 0x75, 0x10, // Report Size (16) - 0x95, 0x06, // Report Count (6) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection - 0x09, 0x39, // Usage (Hat switch) - 0x15, 0x01, // Logical Minimum (1) - 0x25, 0x08, // Logical Maximum (8) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0x3B, 0x01, // Physical Maximum (315) - 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) - 0x75, 0x04, // Report Size (4) - 0x95, 0x01, // Report Count (1) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x0C, // Usage Maximum (0x0C) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x0C, // Report Count (12) - 0x55, 0x00, // Unit Exponent (0) - 0x65, 0x00, // Unit (None) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x02, // Report Count (2) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x08, // Usage Page (LEDs) - 0x09, 0x43, // Usage (Slow Blink On Time) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) - 0x09, 0x44, // Usage (Slow Blink Off Time) - 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) - 0x09, 0x45, // Usage (Fast Blink On Time) - 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) - 0x09, 0x46, // Usage (Fast Blink Off Time) - 0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) - 0xC0, // End Collection - }; - - ////////////// - // RealPlay // - ////////////// - - // Product ID : - // Racing - 0x09B2 - // Sphere - 0x09B3 - // Golf - 0x09B5 - // Pool - 0x09B6 - - // RealPlay Golf is dumped from a real controller. - // The others were force-brutted to be accepted by games - they may be inaccurate. - - static const uint8_t realplay_racing_dev_descriptor[] = { - 0x12, // bLength - 0x01, // bDescriptorType (Device) - 0x00, 0x02, // bcdUSB 2.00 - 0x00, // bDeviceClass (Use class information in the Interface Descriptors) - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - 0x40, // bMaxPacketSize0 64 - 0xB7, 0x14, // idVendor 0x14B7 - 0xB2, 0x09, // idProduct 0x09B2 - 0x00, 0x01, // bcdDevice 2.00 - 0x01, // iManufacturer (String Index) - 0x02, // iProduct (String Index) - 0x00, // iSerialNumber (String Index) - 0x01, // bNumConfigurations 1 - }; - - static const uint8_t realplay_sphere_dev_descriptor[] = { - 0x12, // bLength - 0x01, // bDescriptorType (Device) - 0x00, 0x02, // bcdUSB 2.00 - 0x00, // bDeviceClass (Use class information in the Interface Descriptors) - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - 0x40, // bMaxPacketSize0 64 - 0xB7, 0x14, // idVendor 0x14B7 - 0xB3, 0x09, // idProduct 0x09B3 - 0x00, 0x01, // bcdDevice 2.00 - 0x01, // iManufacturer (String Index) - 0x02, // iProduct (String Index) - 0x00, // iSerialNumber (String Index) - 0x01, // bNumConfigurations 1 - }; - - static const uint8_t realplay_golf_dev_descriptor[] = { - 0x12, // bLength - 0x01, // bDescriptorType (Device) - 0x00, 0x02, // bcdUSB 2.00 - 0x00, // bDeviceClass (Use class information in the Interface Descriptors) - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - 0x40, // bMaxPacketSize0 64 - 0xB7, 0x14, // idVendor 0x14B7 - 0xB5, 0x09, // idProduct 0x09B5 - 0x00, 0x01, // bcdDevice 2.00 - 0x01, // iManufacturer (String Index) - 0x02, // iProduct (String Index) - 0x00, // iSerialNumber (String Index) - 0x01, // bNumConfigurations 1 - }; - - static const uint8_t realplay_pool_dev_descriptor[] = { - 0x12, // bLength - 0x01, // bDescriptorType (Device) - 0x00, 0x02, // bcdUSB 2.00 - 0x00, // bDeviceClass (Use class information in the Interface Descriptors) - 0x00, // bDeviceSubClass - 0x00, // bDeviceProtocol - 0x40, // bMaxPacketSize0 64 - 0xB7, 0x14, // idVendor 0x14B7 - 0xB6, 0x09, // idProduct 0x09B6 - 0x00, 0x01, // bcdDevice 2.00 - 0x01, // iManufacturer (String Index) - 0x02, // iProduct (String Index) - 0x00, // iSerialNumber (String Index) - 0x01, // bNumConfigurations 1 - }; - - static const uint8_t realplay_config_descriptor[] = { - 0x09, // bLength - 0x02, // bDescriptorType (Configuration) - 0x29, 0x00, // wTotalLength 41 - 0x01, // bNumInterfaces 1 - 0x01, // bConfigurationValue - 0x00, // iConfiguration (String Index) - 0x80, // bmAttributes - 0x32, // bMaxPower 100mA - - 0x09, // bLength - 0x04, // bDescriptorType (Interface) - 0x00, // bInterfaceNumber 0 - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints 2 - 0x03, // bInterfaceClass - 0x00, // bInterfaceSubClass - 0x00, // bInterfaceProtocol - 0x00, // iInterface (String Index) - - 0x09, // bLength - 0x21, // bDescriptorType (HID) - 0x11, 0x01, // bcdHID 1.11 - 0x00, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) - 0x85, 0x00, // wDescriptorLength[0] 133 - - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x02, // bEndpointAddress (OUT/H2D) - 0x03, // bmAttributes (Interrupt) - 0x40, 0x00, // wMaxPacketSize 64 - 0x0A, // bInterval 10 (unit depends on device speed) - - 0x07, // bLength - 0x05, // bDescriptorType (Endpoint) - 0x81, // bEndpointAddress (IN/D2H) - 0x03, // bmAttributes (Interrupt) - 0x40, 0x00, // wMaxPacketSize 64 - 0x0A, // bInterval 10 (unit depends on device speed) - }; - - static const uint8_t realplay_hid_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x05, // Usage (Game Pad) - 0xA1, 0x01, // Collection (Application) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x0F, // Logical Maximum (4095) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x0F, // Physical Maximum (4095) - 0x09, 0x30, // Usage (X) - 0x75, 0x0C, // Report Size (12) - 0x95, 0x01, // Report Count (1) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x04, // Report Count (4) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x09, 0x31, // Usage (Y) - 0x75, 0x0C, // Report Size (12) - 0x95, 0x01, // Report Count (1) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x04, // Report Count (4) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x09, 0x32, // Usage (Z) - 0x75, 0x0C, // Report Size (12) - 0x95, 0x01, // Report Count (1) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x04, // Report Count (4) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x09, 0x20, // Usage (0x20) - 0x09, 0x21, // Usage (0x21) - 0x09, 0x22, // Usage (0x22) - 0x09, 0x23, // Usage (0x23) - 0x09, 0x24, // Usage (0x24) - 0x09, 0x25, // Usage (0x25) - 0x09, 0x26, // Usage (0x26) - 0x09, 0x27, // Usage (0x27) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x75, 0x08, // Report Size (8) - 0x95, 0x08, // Report Count (8) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x35, 0x00, // Physical Minimum (0) - 0x45, 0x01, // Physical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x08, // Report Count (8) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x08, // Usage Maximum (0x08) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x09, 0x28, // Usage (0x28) - 0x09, 0x29, // Usage (0x29) - 0x09, 0x2A, // Usage (0x2A) - 0x09, 0x2B, // Usage (0x2B) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection - }; - - struct dfp_buttons_t - { - uint16_t cross : 1; - uint16_t square : 1; - uint16_t circle : 1; - uint16_t triangle : 1; - uint16_t rpaddle_R1 : 1; - uint16_t lpaddle_L1 : 1; - uint16_t R2 : 1; - uint16_t L2 : 1; - uint16_t select : 1; - uint16_t start : 1; - uint16_t R3 : 1; - uint16_t L3 : 1; - uint16_t shifter_back : 1; - uint16_t shifter_fwd : 1; - uint16_t padding : 2; - }; - - struct dfgt_buttons_t - { - uint16_t cross : 1; - uint16_t square : 1; - uint16_t circle : 1; - uint16_t triangle : 1; - uint16_t rpaddle_R1 : 1; - uint16_t lpaddle_L1 : 1; - uint16_t R2 : 1; - uint16_t L2 : 1; - uint16_t select : 1; - uint16_t start : 1; - uint16_t R3 : 1; - uint16_t L3 : 1; - uint16_t shifter_back : 1; - uint16_t shifter_fwd : 1; - uint16_t dial_center : 1; - uint16_t dial_cw : 1; - - uint16_t dial_ccw : 1; - uint16_t rocker_minus : 1; - uint16_t horn : 1; - uint16_t ps_button : 1; - uint16_t padding : 12; - }; - - struct dfp_data_t - { - uint32_t axis_x : 14; - uint32_t buttons : 14; - uint32_t hatswitch : 4; - - uint32_t pad0 : 8; - uint32_t magic1 : 2; //8 //constant? - uint32_t axis_z : 6; //10 - - uint32_t magic2 : 1; //16 //constant? - uint32_t axis_rz : 6; //17 - - uint32_t magic3 : 1; //23 - - uint32_t magic4 : 8; //constant - }; - - struct momo2_data_t - { - uint32_t pad0 : 8; //report id probably - uint32_t axis_x : 10; - uint32_t buttons : 10; - uint32_t padding0 : 4; //32 - - uint8_t padding1; - uint8_t axis_z; - uint8_t axis_rz; - uint8_t padding2; //32 - }; - - // DF or any LG wheel in non-native mode - struct generic_data_t - { - uint32_t axis_x : 10; - uint32_t buttons : 12; - uint32_t pad0 : 2; //vendor - uint32_t axis_y : 8; //constant (0x7f on PC, 0xFF on console?) - - uint32_t hatswitch : 4; - uint32_t pad1 : 4; //vendor - uint32_t axis_z : 8; - uint32_t axis_rz : 8; - uint32_t pad2 : 8; - }; - - // GT Force? - struct gtforce_data_t - { - uint32_t axis_x : 10; - uint32_t buttons : 6; - uint32_t pad0 : 8; - uint32_t axis_y : 8; - - uint32_t axis_z : 8; - uint32_t axis_rz : 8; - - uint32_t pad1 : 16; - }; - - struct random_data_t - { - uint32_t axis_x : 10; - uint32_t buttons : 10; - uint32_t pad1 : 12; - - uint32_t axis_y : 8; //constant - uint32_t axis_z : 8; - uint32_t axis_rz : 8; - uint32_t pad2 : 8; - }; - - struct rb1drumkit_t - { - union u - { - uint16_t buttons; - struct s - { - uint16_t blue : 1; - uint16_t green : 1; - uint16_t red : 1; - uint16_t yellow : 1; - uint16_t orange : 1; - uint16_t something0 : 3; - - uint16_t select : 1; - uint16_t start : 1; - uint16_t something1 : 6; - } s; - } u; - - uint8_t hatswitch; - }; - - void pad_reset_data(generic_data_t* d); - void pad_reset_data(dfp_data_t* d); - void pad_copy_data(PS2WheelTypes type, uint8_t* buf, wheel_data_t& data); - //Convert DF Pro buttons to selected wheel type - uint32_t convert_wt_btn(PS2WheelTypes type, uint32_t inBtn); - } // namespace usb_pad -#endif diff --git a/pcsx2/USB/usb-pad/usb-seamic.cpp b/pcsx2/USB/usb-pad/usb-seamic.cpp index bdae3afad5..90b63249c5 100644 --- a/pcsx2/USB/usb-pad/usb-seamic.cpp +++ b/pcsx2/USB/usb-pad/usb-seamic.cpp @@ -14,11 +14,10 @@ */ #include "PrecompiledHeader.h" -#include "padproxy.h" -#include "usb-pad.h" +#include "USB/usb-pad/usb-pad.h" #include "USB/qemu-usb/desc.h" #include "USB/usb-mic/usb-mic-singstar.h" -#include "USB/shared/inifile_usb.h" +#include "USB/USB.h" namespace usb_pad { @@ -234,32 +233,18 @@ namespace usb_pad // 134 bytes }; - std::list SeamicDevice::ListAPIs() + struct SeamicState : public PadState { - return RegisterPad::instance().Names(); - } + explicit SeamicState(u32 port); - const TCHAR* SeamicDevice::LongAPIName(const std::string& name) - { - auto proxy = RegisterPad::instance().Proxy(name); - if (proxy) - return proxy->Name(); - return nullptr; - } - - typedef struct SeamicState - { - USBDevice dev; - USBDesc desc; - USBDescDevice desc_dev; USBDevice* mic; - Pad* pad; - uint8_t port; - } SeamicState; + }; + + SeamicState::SeamicState(u32 port) : PadState(port, WT_SEGA_SEAMIC) {} static void pad_handle_data(USBDevice* dev, USBPacket* p) { - SeamicState* s = (SeamicState*)dev; + SeamicState* s = USB_CONTAINER_OF(dev, SeamicState, dev); uint8_t data[64]; int ret = 0; @@ -268,15 +253,15 @@ namespace usb_pad switch (p->pid) { case USB_TOKEN_IN: - if (devep == 1 && s->mic) + if (devep == 1) { s->mic->klass.handle_data(s->mic, p); } - else if (devep == 2 && s->pad) + else if (devep == 2) { - ret = s->pad->TokenIn(data, p->iov.size); + ret = s->TokenIn(data, p->iov.size); if (ret > 0) - usb_packet_copy(p, data, MIN((unsigned long)ret, sizeof(data))); + usb_packet_copy(p, data, std::min((size_t)ret, sizeof(data))); else p->status = ret; } @@ -286,8 +271,8 @@ namespace usb_pad } break; case USB_TOKEN_OUT: - usb_packet_copy(p, data, MIN(p->iov.size, sizeof(data))); - ret = s->pad->TokenOut(data, p->iov.size); + usb_packet_copy(p, data, std::min(p->iov.size, sizeof(data))); + ret = s->TokenOut(data, p->iov.size); break; default: fail: @@ -298,9 +283,8 @@ namespace usb_pad static void pad_handle_reset(USBDevice* dev) { - /* XXX: do it */ - SeamicState* s = (SeamicState*)dev; - s->pad->Reset(); + SeamicState* s = USB_CONTAINER_OF(dev, SeamicState, dev); + s->Reset(); s->mic->klass.handle_reset(s->mic); return; } @@ -354,73 +338,72 @@ namespace usb_pad static void pad_handle_destroy(USBDevice* dev) { - SeamicState* s = (SeamicState*)dev; + SeamicState* s = USB_CONTAINER_OF(dev, SeamicState, dev); s->mic->klass.unrealize(s->mic); - s->mic = nullptr; delete s; } - static int pad_open(USBDevice* dev) + const char* SeamicDevice::Name() const { - SeamicState* s = (SeamicState*)dev; - if (s) - { - s->mic->klass.open(s->mic); - return s->pad->Open(); - } - return 1; + return "Sega Seamic"; } - static void pad_close(USBDevice* dev) + const char* SeamicDevice::TypeName() const { - SeamicState* s = (SeamicState*)dev; - if (s) - { - s->mic->klass.close(s->mic); - s->pad->Close(); - } + return "seamic"; } - USBDevice* SeamicDevice::CreateDevice(int port) + std::vector SeamicDevice::SubTypes() const { - std::string varApi; -#ifdef _WIN32 - std::wstring tmp; - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp); - varApi = wstr_to_str(tmp); -#else - LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi); -#endif - PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi); - if (!proxy) - { - Console.WriteLn("USB: PAD: Invalid input API.\n"); - return NULL; - } + return {}; + } - std::string api; + gsl::span SeamicDevice::Bindings(u32 subtype) const + { + // TODO: This is likely wrong. Someone who cares can fix it. + static constexpr const InputBindingInfo bindings[] = { + {"StickLeft", "Stick Left", InputBindingInfo::Type::HalfAxis, CID_STEERING_L, GenericInputBinding::LeftStickLeft}, + {"StickRight", "Stick Right", InputBindingInfo::Type::HalfAxis, CID_STEERING_R, GenericInputBinding::LeftStickRight}, + {"StickUp", "Stick Up", InputBindingInfo::Type::HalfAxis, CID_THROTTLE, GenericInputBinding::LeftStickUp}, + {"StickDown", "Stick Down", InputBindingInfo::Type::HalfAxis, CID_BRAKE, GenericInputBinding::LeftStickDown}, + {"A", "A", InputBindingInfo::Type::Button, CID_BUTTON0, GenericInputBinding::Cross}, + {"B", "B", InputBindingInfo::Type::Button, CID_BUTTON2, GenericInputBinding::Circle}, + {"X", "X", InputBindingInfo::Type::Button, CID_BUTTON1, GenericInputBinding::Square}, + {"Y", "Y", InputBindingInfo::Type::Button, CID_BUTTON3, GenericInputBinding::Triangle}, + {"Z", "Z", InputBindingInfo::Type::Button, CID_BUTTON4, GenericInputBinding::L1}, + {"C", "C", InputBindingInfo::Type::Button, CID_BUTTON5, GenericInputBinding::R1}, + {"DPadUp", "D-Pad Up", InputBindingInfo::Type::Button, CID_DPAD_UP, GenericInputBinding::DPadUp}, + {"DPadDown", "D-Pad Down", InputBindingInfo::Type::Button, CID_DPAD_DOWN, GenericInputBinding::DPadDown}, + {"DPadLeft", "D-Pad Left", InputBindingInfo::Type::Button, CID_DPAD_LEFT, GenericInputBinding::DPadLeft}, + {"DPadRight", "D-Pad Right", InputBindingInfo::Type::Button, CID_DPAD_RIGHT, GenericInputBinding::DPadRight}, + }; + return bindings; + } -#ifdef _WIN32 - if (!LoadSetting(nullptr, port, usb_mic::SingstarDevice::TypeName(), N_DEVICE_API, tmp)) + gsl::span SeamicDevice::Settings(u32 subtype) const + { + static constexpr const SettingInfo info[] = { + {SettingInfo::Type::StringList, "input_device_name", "Input Device", "Selects the device to read audio from.", "", nullptr, + nullptr, nullptr, nullptr, nullptr, &AudioDevice::GetInputDeviceList}, + {SettingInfo::Type::Integer, "input_latency", "Input Latency", "Specifies the latency to the host input device.", + AudioDevice::DEFAULT_LATENCY_STR, "0", "1000", "1", "%dms", nullptr, nullptr, 1.0f}, + }; + return info; + } + + USBDevice* SeamicDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const + { + const usb_mic::SingstarDevice* mic_proxy = + static_cast(RegisterDevice::instance().Device(DEVTYPE_SINGSTAR)); + if (!mic_proxy) return nullptr; - api = wstr_to_str(tmp); -#else - if (!LoadSetting(nullptr, port, usb_mic::SingstarDevice::TypeName(), N_DEVICE_API, api)) - return nullptr; -#endif - USBDevice* mic = usb_mic::SingstarDevice::CreateDevice(port, api); + USBDevice* mic = mic_proxy->CreateDevice(si, port, 0, false, TypeName()); if (!mic) return nullptr; - Pad* pad = proxy->CreateObject(port, TypeName()); - - if (!pad) - return NULL; - - pad->Type(WT_SEGA_SEAMIC); - SeamicState* s = new SeamicState(); + SeamicState* s = new SeamicState(port); s->mic = mic; s->desc.full = &s->desc_dev; @@ -431,41 +414,31 @@ namespace usb_pad if (usb_desc_parse_config(config_descriptor, sizeof(config_descriptor), s->desc_dev) < 0) goto fail; - s->pad = pad; s->dev.speed = USB_SPEED_FULL; s->dev.klass.handle_attach = usb_desc_attach; s->dev.klass.handle_reset = pad_handle_reset; s->dev.klass.handle_control = pad_handle_control; s->dev.klass.handle_data = pad_handle_data; s->dev.klass.unrealize = pad_handle_destroy; - s->dev.klass.open = pad_open; - s->dev.klass.close = pad_close; s->dev.klass.usb_desc = &s->desc; s->dev.klass.product_desc = s->desc.str[2]; //not really used s->port = port; usb_desc_init(&s->dev); usb_ep_init(&s->dev); - pad_handle_reset((USBDevice*)s); + pad_handle_reset(&s->dev); - return (USBDevice*)s; + return &s->dev; fail: - pad_handle_destroy((USBDevice*)s); + pad_handle_destroy(&s->dev); return nullptr; } - int SeamicDevice::Configure(int port, const std::string& api, void* data) + bool SeamicDevice::Freeze(USBDevice* dev, StateWrapper& sw) const { - auto proxy = RegisterPad::instance().Proxy(api); - if (proxy) - return proxy->Configure(port, TypeName(), data); - return RESULT_CANCELED; - } - - int SeamicDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) - { - return 0; + pxFailRel("Not implemented!"); + return true; // SeamicState *s = (SeamicState *)dev; // switch (mode) // { diff --git a/pcsx2/USB/usb-printer/usb-printer.cpp b/pcsx2/USB/usb-printer/usb-printer.cpp index ec2a03f9ce..b1d981a2f2 100644 --- a/pcsx2/USB/usb-printer/usb-printer.cpp +++ b/pcsx2/USB/usb-printer/usb-printer.cpp @@ -14,50 +14,54 @@ */ #include "PrecompiledHeader.h" -#include "../qemu-usb/vl.h" -#include "../shared/inifile_usb.h" -#include "usb-printer.h" -#include "gui/AppConfig.h" - -#ifndef O_BINARY - #define O_BINARY 0 -#endif +#include "USB/qemu-usb/qusb.h" +#include "USB/qemu-usb/USBinternal.h" +#include "USB/usb-printer/usb-printer.h" +#include "USB/USB.h" +#include "common/FileSystem.h" +#include "common/Path.h" +#include "Config.h" +#include "fmt/format.h" +#include "StateWrapper.h" +#include "Host.h" +#include "IconsFontAwesome5.h" namespace usb_printer { typedef struct PrinterState { - USBDevice dev; - USBDesc desc; - USBDescDevice desc_dev; + USBDevice dev{}; + USBDesc desc{}; + USBDescDevice desc_dev{}; - int selected_printer; - int cmd_state; - uint8_t last_command[65]; - int last_command_size; - int print_file; - int width; - int height; - long stride; - int data_size; - long data_pos; + int selected_printer = 0; + int cmd_state = 0; + uint8_t last_command[65] = {}; + int last_command_size = 0; + std::string print_filename; + std::FILE* print_file = nullptr; + int width = 0; + int height = 0; + long stride = 0; + int data_size = 0; + long data_pos = 0; } PrinterState; static void usb_printer_handle_reset(USBDevice* dev) { - PrinterState* s = (PrinterState*)dev; + PrinterState* s = USB_CONTAINER_OF(dev, PrinterState, dev); s->cmd_state = 0; - if (s->print_file > 0) + if (s->print_file) { - close(s->print_file); + std::fclose(s->print_file); + s->print_file = nullptr; } - s->print_file = -1; } static void usb_printer_handle_control(USBDevice* dev, USBPacket* p, int request, int value, - int index, int length, uint8_t* data) + int index, int length, uint8_t* data) { - PrinterState* s = (PrinterState*)dev; + PrinterState* s = USB_CONTAINER_OF(dev, PrinterState, dev); int ret = 0; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); @@ -81,21 +85,23 @@ namespace usb_printer } } - void sony_open_file(PrinterState* s) + static void sony_open_file(PrinterState* s) { - char filepath[1024]; char cur_time_str[32]; const time_t cur_time = time(nullptr); strftime(cur_time_str, sizeof(cur_time_str), "%Y_%m_%d_%H_%M_%S", localtime(&cur_time)); - snprintf(filepath, sizeof(filepath), "%s/print_%s.bmp", - g_Conf->Folders.Snapshots.ToString().ToStdString().c_str(), cur_time_str); - s->print_file = open(filepath, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 666); - if (s->print_file < 0) + + s->print_filename = Path::Combine(EmuFolders::Snapshots, fmt::format("print_{}.bmp", cur_time_str)); + s->print_file = FileSystem::OpenCFile(s->print_filename.c_str(), "wb"); + if (!s->print_file) { - Console.WriteLn("Printer: Sony: Cannot open: %s", filepath); + Host::AddIconOSDMessage("USBPrinterOpen", ICON_FA_EXCLAMATION_TRIANGLE, + fmt::format("Failed to open '{}' for printing.", s->print_filename), Host::OSD_ERROR_DURATION); return; } - Console.WriteLn("Printer: Sony: Saving to... %s", filepath); + + Host::AddIconOSDMessage("USBPrinterOpen", ICON_FA_SAVE, + fmt::format("Printer saving to '{}'...", Path::GetFileName(s->print_filename)), Host::OSD_INFO_DURATION); BMPHeader header = {0}; header.magic = 0x4D42; @@ -106,23 +112,23 @@ namespace usb_printer header.height = s->height; header.planes = 1; header.bpp = 24; - if (write(s->print_file, &header, sizeof(header)) == -1) + if (std::fwrite(&header, sizeof(header), 1, s->print_file) != 1) { Console.Error("Error writing header to print file"); } s->stride = 3 * s->width + 3 - ((3 * s->width + 3) & 3); s->data_pos = 0; - lseek(s->print_file, sizeof(BMPHeader) + s->stride * s->height - 1, SEEK_SET); + FileSystem::FSeek64(s->print_file, sizeof(BMPHeader) + s->stride * s->height - 1, SEEK_SET); char zero = 0; - if (write(s->print_file, &zero, 1) == -1) + if (std::fwrite(&zero, 1, 1, s->print_file) != 1) { Console.Error("Error writing zero padding to header to print file"); } } - void sony_write_data(PrinterState* s, int size, uint8_t* data) + static void sony_write_data(PrinterState* s, int size, uint8_t* data) { for (int i = 0; i < size; i++) { @@ -134,24 +140,42 @@ namespace usb_printer Console.WriteLn("Printer: Sony: error: pos_out=0x%x", pos_out); break; } - lseek(s->print_file, sizeof(BMPHeader) + pos_out + 2 - s->data_pos % 3, SEEK_SET); - if (write(s->print_file, data + i, 1) == -1) + // print_file might be null if we're loading a state + if (s->print_file) { - Console.Error("Error writing data to print file"); + FileSystem::FSeek64(s->print_file, sizeof(BMPHeader) + pos_out + 2 - s->data_pos % 3, SEEK_SET); + + if (std::fwrite(data + i, 1, 1, s->print_file) != 1) + { + Console.Error("Error writing data to print file"); + } } - s->data_pos ++; + s->data_pos++; } } - void sony_close_file(PrinterState* s) + static void sony_close_file(PrinterState* s) { Console.WriteLn("Printer: Sony: done."); - if (s->print_file >= 0) + if (s->print_file) { - close(s->print_file); + std::fclose(s->print_file); + s->print_file = nullptr; + s->print_filename = {}; } - s->print_file = -1; + } + + static void sony_cancel_file(PrinterState* s) + { + if (!s->print_file) + return; + + Console.Warning("Removing incomplete printer file '%s'", s->print_filename.c_str()); + std::fclose(s->print_file); + s->print_file = nullptr; + FileSystem::DeleteFilePath(s->print_filename.c_str()); + s->print_filename = {}; } static void usb_printer_handle_data_sony(USBDevice* dev, USBPacket* p) @@ -162,47 +186,32 @@ namespace usb_printer uint8_t ret[256]; }; const struct req_reply commands[] = - { { - {0x1B, 0xE0, 0x00, 0x00, 0x00, 0x0E, 0x00}, - {0x0D, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x24, 0x38, 0x03, 0xF2, 0x02, 0x74} - }, - { - {0x1B, 0xCF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00}, - {0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }, - { - {0x1B, 0xCF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00}, - {0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x00, 0x07} - }, - { - {0x1B, 0xCF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00}, - {0x00, 0x00, 0x00, 0x12, 0x03, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x00, 0x04} - }, - { - {0x1B, 0xCF, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00}, - {0x00, 0x00, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x18, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00} - }, - { - {0x1B, 0xCF, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00}, - {0x00, 0x00, 0x00, 0x0E, 0x05, 0x00, 0x02, 0x74, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00} - }, - { - {0x1B, 0x12, 0x01, 0x00, 0x00, 0x19, 0x00}, - {0x02, 0xC0, 0x00, 0x15, 0x03, 0xF2, 0x02, 0x74, 0x03, 0xF2, 0x02, 0x74, 0x01, 0x33, 0x00, 0x00, - 0x15, 0x01, 0x03, 0x23, 0x30, 0x31, 0x2E, 0x30, 0x30} - } - }; + {{0x1B, 0xE0, 0x00, 0x00, 0x00, 0x0E, 0x00}, + {0x0D, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x24, 0x38, 0x03, 0xF2, 0x02, 0x74}}, + {{0x1B, 0xCF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00}, + {0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x1B, 0xCF, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00}, + {0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x07}}, + {{0x1B, 0xCF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00}, + {0x00, 0x00, 0x00, 0x12, 0x03, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x04}}, + {{0x1B, 0xCF, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00}, + {0x00, 0x00, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x18, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00}}, + {{0x1B, 0xCF, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00}, + {0x00, 0x00, 0x00, 0x0E, 0x05, 0x00, 0x02, 0x74, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}}, + {{0x1B, 0x12, 0x01, 0x00, 0x00, 0x19, 0x00}, + {0x02, 0xC0, 0x00, 0x15, 0x03, 0xF2, 0x02, 0x74, 0x03, 0xF2, 0x02, 0x74, 0x01, 0x33, 0x00, 0x00, + 0x15, 0x01, 0x03, 0x23, 0x30, 0x31, 0x2E, 0x30, 0x30}}}; const uint8_t set_size[] = {0x00, 0x00, 0x00, 0x00, 0xa7, 0x00}; const uint8_t set_data[] = {0x1b, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00}; const uint8_t print_compl[] = {0x1b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00}; - PrinterState* s = (PrinterState*)dev; + PrinterState* s = USB_CONTAINER_OF(dev, PrinterState, dev); //const uint8_t ep_nr = p->ep->nr; //const uint8_t ep_type = p->ep->type; @@ -275,19 +284,16 @@ namespace usb_printer static void usb_printer_handle_destroy(USBDevice* dev) { - PrinterState* s = (PrinterState*)dev; + PrinterState* s = USB_CONTAINER_OF(dev, PrinterState, dev); + sony_cancel_file(s); delete s; } - USBDevice* PrinterDevice::CreateDevice(int port) + USBDevice* PrinterDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const { PrinterState* s = new PrinterState(); - std::string api = *PrinterDevice::ListAPIs().begin(); - uint32_t subtype = GetSelectedSubtype(std::make_pair(port, TypeName())); - if (subtype >= sizeof(sPrinters) / sizeof(sPrinters[0])) { - subtype = 0; - } - s->selected_printer = subtype; + + s->selected_printer = std::min(subtype, std::size(sPrinters)); s->dev.speed = USB_SPEED_FULL; s->desc.full = &s->desc_dev; @@ -312,22 +318,57 @@ namespace usb_printer usb_desc_init(&s->dev); usb_ep_init(&s->dev); - usb_printer_handle_reset((USBDevice*)s); - return (USBDevice*)s; + usb_printer_handle_reset(&s->dev); + return &s->dev; fail: - usb_printer_handle_destroy((USBDevice*)s); + usb_printer_handle_destroy(&s->dev); return nullptr; } - int PrinterDevice::Configure(int port, const std::string& api, void* data) + const char* PrinterDevice::Name() const { - return 0; + return "Printer"; } - int PrinterDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data) + const char* PrinterDevice::TypeName() const { - return 0; + return "printer"; + } + + bool PrinterDevice::Freeze(USBDevice* dev, StateWrapper& sw) const + { + PrinterState* s = USB_CONTAINER_OF(dev, PrinterState, dev); + + if (!sw.DoMarker("PrinterDevice")) + return false; + + sw.Do(&s->selected_printer); + sw.Do(&s->cmd_state); + sw.DoBytes(&s->last_command, sizeof(s->last_command)); + sw.Do(&s->last_command_size); + sw.Do(&s->width); + sw.Do(&s->height); + sw.Do(&s->stride); + sw.Do(&s->data_size); + sw.Do(&s->data_pos); + + // toss any file being saved when we're loading, since we'd probably + // end up with a corrupted file otherwise + if (sw.IsReading()) + sony_cancel_file(s); + + return true; + } + + std::vector PrinterDevice::SubTypes() const + { + std::vector ret; + for (uint32_t i = 0; i < sizeof(sPrinters) / sizeof(sPrinters[0]); i++) + { + ret.push_back(sPrinters[i].commercial_name); + } + return ret; } } // namespace usb_printer diff --git a/pcsx2/USB/usb-printer/usb-printer.h b/pcsx2/USB/usb-printer/usb-printer.h index 24489cf313..e0b1b5c9ca 100644 --- a/pcsx2/USB/usb-printer/usb-printer.h +++ b/pcsx2/USB/usb-printer/usb-printer.h @@ -13,11 +13,10 @@ * If not, see . */ -#ifndef USBPRINTER_H -#define USBPRINTER_H +#pragma once -#include "../deviceproxy.h" -#include "../qemu-usb/desc.h" +#include "USB/deviceproxy.h" +#include "USB/qemu-usb/desc.h" #define GET_DEVICE_ID 0 #define GET_PORT_STATUS 1 @@ -121,40 +120,15 @@ namespace usb_printer }, }; - static const char* APINAME = "default"; - - class PrinterDevice + class PrinterDevice final : public DeviceProxy { public: - virtual ~PrinterDevice() {} - static USBDevice* CreateDevice(int port); - static const TCHAR* Name() - { - return TEXT("Printer"); - } - static const char* TypeName() - { - return "printer"; - } - static std::list ListAPIs() - { - return std::list{APINAME}; - } - static const TCHAR* LongAPIName(const std::string& name) - { - return TEXT("Default"); - } - static int Configure(int port, const std::string& api, void* data); - static int Freeze(FreezeAction mode, USBDevice* dev, void* data); - static std::vector SubTypes() - { - std::vector ret; - for (uint32_t i = 0; i < sizeof(sPrinters) / sizeof(sPrinters[0]); i++) - { - ret.push_back(sPrinters[i].commercial_name); - } - return ret; - } + USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override; + const char* Name() const override; + const char* TypeName() const override; + + bool Freeze(USBDevice* dev, StateWrapper& sw) const override; + std::vector SubTypes() const override; }; #pragma pack(push, 1) @@ -173,4 +147,3 @@ namespace usb_printer #pragma pack(pop) } // namespace usb_printer -#endif diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 5b142de710..c6875af46b 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -273,11 +273,18 @@ bool VMManager::Internal::InitializeGlobals() return false; } + if (USBinit() != 0) + { + Host::ReportErrorAsync("Error", "Failed to initialize USB (USBinit())"); + return false; + } + return true; } void VMManager::Internal::ReleaseGlobals() { + USBshutdown(); SPU2shutdown(); GSshutdown(); @@ -993,14 +1000,13 @@ bool VMManager::Initialize(VMBootParameters boot_params) }; Console.WriteLn("Opening USB..."); - if (USBinit() != 0 || USBopen(g_host_display->GetWindowInfo()) != 0) + if (!USBopen()) { Host::ReportErrorAsync("Startup Error", "Failed to initialize USB."); return false; } ScopedGuard close_usb = []() { USBclose(); - USBshutdown(); }; Console.WriteLn("Opening FW..."); @@ -1140,7 +1146,6 @@ void VMManager::Shutdown(bool save_resume_state) GetMTGS().WaitForClose(); } - USBshutdown(); PADshutdown(); DEV9shutdown(); @@ -1804,6 +1809,7 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config) CheckForSPU2ConfigChanges(old_config); CheckForDEV9ConfigChanges(old_config); CheckForMemoryCardConfigChanges(old_config); + USB::CheckForConfigChanges(old_config); if (EmuConfig.EnableCheats != old_config.EnableCheats || EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches || diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 8b9e81b331..bccc33ad59 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -31,7 +31,7 @@ #include "GS.h" #include "CDVD/CDVD.h" -#include "USB/USB.h" +#include "USB/USBNull.h" #include "Elfheader.h" #include "Patch.h" #include "R5900Exceptions.h" diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 310c44b90b..cd52c95443 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -23,7 +23,7 @@ #include "SPU2/spu2.h" #include "SysThreads.h" #include "DEV9/DEV9.h" -#include "USB/USB.h" +#include "USB/USBNull.h" #include "PAD/Gamepad.h" #include "ConsoleLogger.h" diff --git a/pcsx2/gui/SysCoreThread.cpp b/pcsx2/gui/SysCoreThread.cpp index a1edea4946..4a62792fd5 100644 --- a/pcsx2/gui/SysCoreThread.cpp +++ b/pcsx2/gui/SysCoreThread.cpp @@ -33,7 +33,7 @@ extern WindowInfo g_gs_window_info; #include "FW.h" #include "SPU2/spu2.h" #include "DEV9/DEV9.h" -#include "USB/USB.h" +#include "USB/USBNull.h" #include "MemoryCardFile.h" #include "PAD/Gamepad.h" #include "PerformanceMetrics.h" diff --git a/pcsx2/gui/SysState.cpp b/pcsx2/gui/SysState.cpp index e89eed4ff8..ccb33980fb 100644 --- a/pcsx2/gui/SysState.cpp +++ b/pcsx2/gui/SysState.cpp @@ -23,7 +23,7 @@ #include "common/StringUtil.h" #include "SPU2/spu2.h" -#include "USB/USB.h" +#include "USB/USBNull.h" #include "PAD/Gamepad.h" #include "ConsoleLogger.h" diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index e1e6fd0e0e..3aad85624c 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -378,51 +378,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -482,6 +437,7 @@ + true @@ -893,58 +849,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -963,6 +867,7 @@ + @@ -1091,9 +996,6 @@ - - - @@ -1109,9 +1011,6 @@ {d6973076-9317-4ef2-a0b8-b7a18ac0713e} - - {47afdbef-f15f-4bc0-b436-5be443c3f80f} - {0fae817d-9a32-4830-857e-81da57246e16} false diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index 92f652c3e9..3e5cfc0c48 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -208,48 +208,6 @@ {df9de75c-2272-4f73-b2a0-4f9f492ba1e9} - - {f128e163-0f30-43eb-80a1-4739a6313c8f} - - - {5a206eba-a8b6-44ef-98e7-eb0384c9a896} - - - {c63d7e06-bbf9-48ec-aa38-d122aa6648cf} - - - {aee88110-a71e-4896-8b22-73e3198eb30a} - - - {1aa4f41d-451c-4599-9aa7-e2f51f5b467d} - - - {9c8b3479-af75-4999-b265-d0c8c66d0954} - - - {e4b2d8b4-a9fb-4c6d-b247-2112afd8d099} - - - {fe77f40c-84c0-4a06-affb-b6e7fb09ce49} - - - {a478e196-ac99-4a12-bfbb-2a7a3128d6e9} - - - {96b523da-ac91-4f95-81af-8df223188783} - - - {a12c76e1-5876-4ce2-aec6-427270102eed} - - - {b067682e-741d-4414-89ef-8ffc22aef8dc} - - - {8640e8ca-7d79-4221-b1bf-35bc142a9add} - - - {343981c6-ca99-462d-9b20-0500a23ae4cd} - {e1cbcaf6-9f65-4f14-9e89-27dd0f10e047} @@ -1289,141 +1247,6 @@ System\Ps2\DEV9 - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\usb-msd - - - System\Ps2\USB\usb-pad - - - System\Ps2\USB\usb-pad - - - System\Ps2\USB\usb-pad\lg - - - System\Ps2\USB\usb-pad - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\shared - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-msd - - - System\Ps2\USB\usb-printer - - - System\Ps2\USB\shared - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\raw - - - System\Ps2\USB\usb-pad\raw - - - System\Ps2\USB\usb-pad - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\Win32 - - - System\Ps2\USB\shared - - - System\Ps2\USB\shared - - - System\Ps2\USB\shared - System\Ps2\PAD @@ -1799,6 +1622,9 @@ System\Ps2\Iop + + System\Ps2\USB + @@ -2449,162 +2275,6 @@ System\Ps2\DEV9 - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB - - - System\Ps2\USB\readerwriterqueue - - - System\Ps2\USB\readerwriterqueue - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\usb-msd - - - System\Ps2\USB\usb-pad - - - System\Ps2\USB\usb-pad - - - System\Ps2\USB\usb-pad\lg - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\shared - - - System\Ps2\USB\usb-mic - - - System\Ps2\USB\usb-printer - - - System\Ps2\USB\shared - - - System\Ps2\USB\qemu-usb - - - System\Ps2\USB\usb-hid - - - System\Ps2\USB\usb-eyetoy - - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\raw - - - System\Ps2\USB\usb-pad\raw - - - System\Ps2\USB\Win32 - - - System\Ps2\USB\shared - - - System\Ps2\USB\shared - - - System\Ps2\USB\shared - - - System\Ps2\USB\Win32 - System\Ps2\PAD @@ -2993,6 +2663,9 @@ System\Ps2\Iop + + System\Ps2\USB + @@ -3007,15 +2680,6 @@ System\Ps2\SPU2 - - System\Ps2\USB\usb-pad\dx - - - System\Ps2\USB\usb-pad\raw - - - System\Ps2\USB\Win32 - System\Ps2\PAD diff --git a/pcsx2/pcsx2core.vcxproj b/pcsx2/pcsx2core.vcxproj index 84ab6c4160..147e0aacd6 100644 --- a/pcsx2/pcsx2core.vcxproj +++ b/pcsx2/pcsx2core.vcxproj @@ -333,9 +333,34 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -666,6 +691,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/pcsx2core.vcxproj.filters b/pcsx2/pcsx2core.vcxproj.filters index f6f3b8979b..650eac372d 100644 --- a/pcsx2/pcsx2core.vcxproj.filters +++ b/pcsx2/pcsx2core.vcxproj.filters @@ -241,6 +241,39 @@ {78c9db9c-9c7c-4385-90e7-9fa71b922f60} + + {e068b724-9319-42e5-9ea7-63d80989ea1d} + + + {f82a2be4-24a1-4dd8-9395-c53d0e1c4ddb} + + + {58074375-dbbe-4137-bbe5-54478d1a97c7} + + + {b7da726d-4e91-48d4-a987-b624e87e4481} + + + {48a0208f-5734-4e6c-bb4d-3c16e0333a81} + + + {001fa220-df32-4da7-ba7e-2a7eca5cdb78} + + + {20789ef3-7c0e-41ac-babd-03a9be9fe994} + + + {c59653b3-87d6-4b11-b9e3-f0543117ca27} + + + {cab6864f-999a-4002-bd85-e1452c62efb8} + + + {72ca905b-3eaa-425a-b77a-3fe83869af72} + + + {b8542664-8208-48ad-bd47-425a316f293c} + @@ -1217,9 +1250,6 @@ System\Ps2\SPU2 - - System\Ps2\USB - Host @@ -1317,7 +1347,87 @@ System\Ps2\Iop - + + System\Ps2\USB + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\shared + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-printer + + + System\Ps2\USB\usb-msd + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-hid + + + System\Ps2\USB\usb-pad + + + System\Ps2\USB\usb-pad + + + System\Ps2\USB\usb-pad + + + System\Ps2\USB\usb-pad\lg + + + System\Ps2\USB\usb-lightgun + + + System + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB + + + System\Ps2\USB\usb-pad + @@ -1821,9 +1931,6 @@ System\Ps2\DEV9 - - System\Ps2\USB - System\Ps2\GS @@ -2193,7 +2300,99 @@ System\Ps2\Iop - + + System\Ps2\USB + + + System\Ps2\USB + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\qemu-usb + + + System\Ps2\USB\readerwriterqueue + + + System\Ps2\USB\readerwriterqueue + + + System\Ps2\USB\shared + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-eyetoy + + + System\Ps2\USB\usb-printer + + + System\Ps2\USB\usb-msd + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-hid + + + System\Ps2\USB\usb-pad + + + System\Ps2\USB\usb-pad\lg + + + System\Ps2\USB\usb-lightgun + + + System + + + System\Ps2\USB\usb-mic + + + System\Ps2\USB\usb-pad + @@ -2218,4 +2417,4 @@ System\Ps2\Debug\rdebug - + \ No newline at end of file diff --git a/pcsx2/ps2/Iop/IopHwRead.cpp b/pcsx2/ps2/Iop/IopHwRead.cpp index 483f2f36d7..7fabd4a924 100644 --- a/pcsx2/ps2/Iop/IopHwRead.cpp +++ b/pcsx2/ps2/Iop/IopHwRead.cpp @@ -22,7 +22,11 @@ #include "FW.h" #include "SPU2/spu2.h" #include "DEV9/DEV9.h" +#ifdef PCSX2_CORE #include "USB/USB.h" +#else +#include "USB/USBNull.h" +#endif #include "IopCounters.h" #include "IopDma.h" diff --git a/pcsx2/ps2/Iop/IopHwWrite.cpp b/pcsx2/ps2/Iop/IopHwWrite.cpp index a1e0378ef8..80e400338f 100644 --- a/pcsx2/ps2/Iop/IopHwWrite.cpp +++ b/pcsx2/ps2/Iop/IopHwWrite.cpp @@ -21,7 +21,11 @@ #include "CDVD/Ps1CD.h" #include "SPU2/spu2.h" #include "DEV9/DEV9.h" +#ifdef PCSX2_CORE #include "USB/USB.h" +#else +#include "USB/USBNull.h" +#endif #include "IopCounters.h" #include "IopDma.h" #include "R3000A.h"