diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index e265de612..692b290e2 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -6,7 +6,13 @@ set(CMAKE_AUTORCC ON) find_package(Threads REQUIRED) -add_library(plat STATIC qt.c qt_main.cpp qt_platform.cpp cpp11_thread.cpp) +add_library(plat STATIC + qt.c + qt_main.cpp + qt_platform.cpp + sdl_joystick.cpp + cpp11_thread.cpp +) add_library(ui STATIC qt_ui.cpp qt_cdrom.c @@ -69,6 +75,9 @@ add_library(ui STATIC qt_deviceconfig.cpp qt_deviceconfig.hpp qt_deviceconfig.ui + qt_joystickconfiguration.cpp + qt_joystickconfiguration.hpp + qt_joystickconfiguration.ui qt_filefield.cpp qt_filefield.hpp diff --git a/src/qt/qt_joystickconfiguration.cpp b/src/qt/qt_joystickconfiguration.cpp new file mode 100644 index 000000000..f87ea8b3c --- /dev/null +++ b/src/qt/qt_joystickconfiguration.cpp @@ -0,0 +1,183 @@ +#include "qt_joystickconfiguration.hpp" +#include "ui_qt_joystickconfiguration.h" + +extern "C" { +#include <86box/device.h> +#include <86box/gameport.h> +} + + +#include +#include +#include +#include "qt_models_common.hpp" + +JoystickConfiguration::JoystickConfiguration(int type, int joystick_nr, QWidget *parent) : + QDialog(parent), + ui(new Ui::JoystickConfiguration), + type(type), + joystick_nr(joystick_nr) +{ + ui->setupUi(this); + + auto model = ui->comboBoxDevice->model(); + Models::AddEntry(model, "None", 0); + for (int c = 0; c < joysticks_present; c++) { + Models::AddEntry(model, plat_joystick_state[c].name, c+1); + } + + ui->comboBoxDevice->setCurrentIndex(joystick_state[joystick_nr].plat_joystick_nr); +} + +JoystickConfiguration::~JoystickConfiguration() +{ + delete ui; +} + +int JoystickConfiguration::selectedDevice() { + return ui->comboBoxDevice->currentIndex(); +} + +int JoystickConfiguration::selectedAxis(int axis) { + auto* cbox = findChild(QString("cboxAxis%1").arg(QString::number(axis))); + if (cbox == nullptr) { + return 0; + } + return cbox->currentIndex(); +} + +int JoystickConfiguration::selectedButton(int button) { + auto* cbox = findChild(QString("cboxButton%1").arg(QString::number(button))); + if (cbox == nullptr) { + return 0; + } + return cbox->currentIndex(); +} + +int JoystickConfiguration::selectedPov(int pov) { + auto* cbox = findChild(QString("cboxPov%1").arg(QString::number(pov))); + if (cbox == nullptr) { + return 0; + } + return cbox->currentIndex(); +} + +void JoystickConfiguration::on_comboBoxDevice_currentIndexChanged(int index) { + for (auto w : widgets) { + ui->ct->removeWidget(w); + } + + if (index == 0) { + return; + } + + int joystick = index - 1; + int row = 0; + for (int c = 0; c < joystick_get_axis_count(type); c++) { + /*Combo box*/ + auto label = new QLabel(joystick_get_axis_name(type, c), this); + auto cbox = new QComboBox(this); + cbox->setObjectName(QString("cboxAxis%1").arg(QString::number(c))); + auto model = cbox->model(); + + for (int d = 0; d < plat_joystick_state[joystick].nr_axes; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].axis[d].name, 0); + } + + for (int d = 0; d < plat_joystick_state[joystick].nr_povs; d++) { + Models::AddEntry(model, QString("%1 (X axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + Models::AddEntry(model, QString("%1 (Y axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + } + + for (int d = 0; d < plat_joystick_state[joystick].nr_sliders; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].slider[d].name, 0); + } + + int nr_axes = plat_joystick_state[joystick].nr_axes; + int nr_povs = plat_joystick_state[joystick].nr_povs; + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + if (mapping & POV_X) + cbox->setCurrentIndex(nr_axes + (mapping & 3) * 2); + else if (mapping & POV_Y) + cbox->setCurrentIndex(nr_axes + (mapping & 3) * 2 + 1); + else if (mapping & SLIDER) + cbox->setCurrentIndex(nr_axes + nr_povs * 2 + (mapping & 3)); + else + cbox->setCurrentIndex(mapping); + + ui->ct->addWidget(label, row, 0); + ui->ct->addWidget(cbox, row, 1); + + widgets.append(label); + widgets.append(cbox); + + ++row; + } + + for (int c = 0; c < joystick_get_button_count(type); c++) { + auto label = new QLabel(joystick_get_button_name(type, c), this); + auto cbox = new QComboBox(this); + cbox->setObjectName(QString("cboxButton%1").arg(QString::number(c))); + auto model = cbox->model(); + + for (int d = 0; d < plat_joystick_state[joystick].nr_buttons; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].button[d].name, 0); + } + + cbox->setCurrentIndex(joystick_state[joystick_nr].button_mapping[c]); + + ui->ct->addWidget(label, row, 0); + ui->ct->addWidget(cbox, row, 1); + + widgets.append(label); + widgets.append(cbox); + + ++row; + } + + for (int c = 0; c < joystick_get_pov_count(type) * 2; c++) { + QLabel* label; + if (c & 1) { + label = new QLabel(QString("%1 (Y axis)").arg(joystick_get_pov_name(type, c/2)), this); + } else { + label = new QLabel(QString("%1 (X axis)").arg(joystick_get_pov_name(type, c/2)), this); + } + auto cbox = new QComboBox(this); + cbox->setObjectName(QString("cboxPov%1").arg(QString::number(c))); + auto model = cbox->model(); + + for (int d = 0; d < plat_joystick_state[joystick].nr_povs; d++) { + Models::AddEntry(model, QString("%1 (X axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + Models::AddEntry(model, QString("%1 (Y axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + } + + for (int d = 0; d < plat_joystick_state[joystick].nr_axes; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].axis[d].name, 0); + } + + int mapping = joystick_state[joystick_nr].pov_mapping[c][0]; + int nr_povs = plat_joystick_state[joystick].nr_povs; + if (mapping & POV_X) + cbox->setCurrentIndex((mapping & 3) * 2); + else if (mapping & POV_Y) + cbox->setCurrentIndex((mapping & 3)*2 + 1); + else + cbox->setCurrentIndex(mapping + nr_povs * 2); + + mapping = joystick_state[joystick_nr].pov_mapping[c][1]; + if (mapping & POV_X) + cbox->setCurrentIndex((mapping & 3)*2); + else if (mapping & POV_Y) + cbox->setCurrentIndex((mapping & 3)*2 + 1); + else + cbox->setCurrentIndex(mapping + nr_povs*2); + + ui->ct->addWidget(label, row, 0); + ui->ct->addWidget(cbox, row, 1); + + widgets.append(label); + widgets.append(cbox); + + ++row; + } +} diff --git a/src/qt/qt_joystickconfiguration.hpp b/src/qt/qt_joystickconfiguration.hpp new file mode 100644 index 000000000..b6882c52b --- /dev/null +++ b/src/qt/qt_joystickconfiguration.hpp @@ -0,0 +1,32 @@ +#ifndef QT_JOYSTICKCONFIGURATION_HPP +#define QT_JOYSTICKCONFIGURATION_HPP + +#include + +namespace Ui { +class JoystickConfiguration; +} + +class JoystickConfiguration : public QDialog +{ + Q_OBJECT + +public: + explicit JoystickConfiguration(int type, int joystick_nr, QWidget *parent = nullptr); + ~JoystickConfiguration(); + + int selectedDevice(); + int selectedAxis(int axis); + int selectedButton(int button); + int selectedPov(int pov); +private slots: + void on_comboBoxDevice_currentIndexChanged(int index); + +private: + Ui::JoystickConfiguration *ui; + QList widgets; + int type; + int joystick_nr; +}; + +#endif // QT_JOYSTICKCONFIGURATION_HPP diff --git a/src/qt/qt_joystickconfiguration.ui b/src/qt/qt_joystickconfiguration.ui new file mode 100644 index 000000000..abe17b5cc --- /dev/null +++ b/src/qt/qt_joystickconfiguration.ui @@ -0,0 +1,87 @@ + + + JoystickConfiguration + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + Device + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + buttonBox + accepted() + JoystickConfiguration + accept() + + + 223 + 278 + + + 199 + 149 + + + + + buttonBox + rejected() + JoystickConfiguration + reject() + + + 223 + 278 + + + 199 + 149 + + + + + diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index e2a227472..548135ec3 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -67,9 +67,6 @@ int kbd_req_capture = 0; int hide_status_bar = 0; uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US -plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; -joystick_t joystick_state[MAX_JOYSTICKS]; - int stricmp(const char* s1, const char* s2) { return QByteArray(s1).compare(s2, Qt::CaseInsensitive); @@ -380,9 +377,6 @@ void dynld_close(void *handle) delete reinterpret_cast(handle); } -void joystick_init(void) {} -void joystick_close(void) {} -void joystick_process(void) {} void startblit() { blitmx_contention++; diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 8a8d8e1bf..04c8a8f3d 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -11,7 +11,9 @@ extern "C" { #include <86box/gameport.h> } +#include "qt_models_common.hpp" #include "qt_deviceconfig.hpp" +#include "qt_joystickconfiguration.hpp" SettingsInput::SettingsInput(QWidget *parent) : QWidget(parent), @@ -73,13 +75,7 @@ void SettingsInput::onCurrentMachineChanged(int machineId) { removeRows = joystickModel->rowCount(); selectedRow = 0; while (joyName) { - int row = joystickModel->rowCount(); - joystickModel->insertRow(row); - auto idx = joystickModel->index(row, 0); - - joystickModel->setData(idx, joyName, Qt::DisplayRole); - joystickModel->setData(idx, i, Qt::UserRole); - + int row = Models::AddEntry(joystickModel, joyName, i); if (i == joystick_type) { selectedRow = row - removeRows; } @@ -112,3 +108,80 @@ void SettingsInput::on_pushButtonConfigureMouse_clicked() { int mouseId = ui->comboBoxMouse->currentData().toInt(); DeviceConfig::ConfigureDevice(mouse_get_device(mouseId)); } + +static int get_axis(JoystickConfiguration& jc, int axis, int joystick_nr) { + int axis_sel = jc.selectedAxis(axis); + int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_axes; + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_povs; + + if (axis_sel < nr_axes) { + return axis_sel; + } + + axis_sel -= nr_axes; + if (axis_sel < nr_povs * 2) { + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); + } + axis_sel -= nr_povs; + + return SLIDER | (axis_sel >> 1); +} + +static int get_pov(JoystickConfiguration& jc, int pov, int joystick_nr) { + int pov_sel = jc.selectedPov(pov); + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2; + + if (pov_sel < nr_povs) + { + if (pov_sel & 1) + return POV_Y | (pov_sel >> 1); + else + return POV_X | (pov_sel >> 1); + } + + return pov_sel - nr_povs; +} + +static void updateJoystickConfig(int type, int joystick_nr, QWidget* parent) { + JoystickConfiguration jc(type, joystick_nr, parent); + switch (jc.exec()) { + case QDialog::Rejected: + return; + case QDialog::Accepted: + break; + } + + joystick_state[joystick_nr].plat_joystick_nr = jc.selectedDevice(); + if (joystick_state[joystick_nr].plat_joystick_nr) { + for (int c = 0; c < joystick_get_axis_count(type); c++) { + joystick_state[joystick_nr].axis_mapping[c] = get_axis(jc, c, joystick_nr); + } + for (int c = 0; c < joystick_get_button_count(type); c++) { + joystick_state[joystick_nr].button_mapping[c] = jc.selectedButton(c); + } + for (int c = 0; c < joystick_get_button_count(type); c++) { + joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(jc, c, joystick_nr); + joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(jc, c, joystick_nr); + } + } +} + +void SettingsInput::on_pushButtonJoystick1_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 0, this); +} + +void SettingsInput::on_pushButtonJoystick2_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 1, this); +} + +void SettingsInput::on_pushButtonJoystick3_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 2, this); +} + +void SettingsInput::on_pushButtonJoystick4_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 3, this); +} + diff --git a/src/qt/qt_settingsinput.hpp b/src/qt/qt_settingsinput.hpp index f69453dea..f9e44740d 100644 --- a/src/qt/qt_settingsinput.hpp +++ b/src/qt/qt_settingsinput.hpp @@ -24,6 +24,10 @@ private slots: void on_pushButtonConfigureMouse_clicked(); void on_comboBoxJoystick_currentIndexChanged(int index); void on_comboBoxMouse_currentIndexChanged(int index); + void on_pushButtonJoystick1_clicked(); + void on_pushButtonJoystick2_clicked(); + void on_pushButtonJoystick3_clicked(); + void on_pushButtonJoystick4_clicked(); private: Ui::SettingsInput *ui; diff --git a/src/qt/sdl_joystick.cpp b/src/qt/sdl_joystick.cpp new file mode 100644 index 000000000..13adfba44 --- /dev/null +++ b/src/qt/sdl_joystick.cpp @@ -0,0 +1,159 @@ +// Lifted from wx-sdl2-joystick.c in PCem + +#include + +extern "C" { +#include <86box/device.h> +#include <86box/gameport.h> + +int joysticks_present; +joystick_t joystick_state[MAX_JOYSTICKS]; +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +static SDL_Joystick *sdl_joy[MAX_PLAT_JOYSTICKS]; +} + +void joystick_init() { + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) { + return; + } + joysticks_present = SDL_NumJoysticks(); + + memset(sdl_joy, 0, sizeof(sdl_joy)); + for (int c = 0; c < joysticks_present; c++) + { + sdl_joy[c] = SDL_JoystickOpen(c); + + if (sdl_joy[c]) + { + int d; + + strncpy(plat_joystick_state[c].name, SDL_JoystickNameForIndex(c), 64); + plat_joystick_state[c].nr_axes = SDL_JoystickNumAxes(sdl_joy[c]); + plat_joystick_state[c].nr_buttons = SDL_JoystickNumButtons(sdl_joy[c]); + plat_joystick_state[c].nr_povs = SDL_JoystickNumHats(sdl_joy[c]); + + for (d = 0; d < std::min(plat_joystick_state[c].nr_axes, 8); d++) + { + sprintf(plat_joystick_state[c].axis[d].name, "Axis %i", d); + plat_joystick_state[c].axis[d].id = d; + } + for (d = 0; d < std::min(plat_joystick_state[c].nr_buttons, 8); d++) + { + sprintf(plat_joystick_state[c].button[d].name, "Button %i", d); + plat_joystick_state[c].button[d].id = d; + } + for (d = 0; d < std::min(plat_joystick_state[c].nr_povs, 4); d++) + { + sprintf(plat_joystick_state[c].pov[d].name, "POV %i", d); + plat_joystick_state[c].pov[d].id = d; + } + } + } +} + +void joystick_close() +{ + int c; + + for (c = 0; c < joysticks_present; c++) + { + if (sdl_joy[c]) + SDL_JoystickClose(sdl_joy[c]); + } +} + +static int joystick_get_axis(int joystick_nr, int mapping) +{ + if (mapping & POV_X) + { + switch (plat_joystick_state[joystick_nr].p[mapping & 3]) + { + case SDL_HAT_LEFTUP: case SDL_HAT_LEFT: case SDL_HAT_LEFTDOWN: + return -32767; + + case SDL_HAT_RIGHTUP: case SDL_HAT_RIGHT: case SDL_HAT_RIGHTDOWN: + return 32767; + + default: + return 0; + } + } + else if (mapping & POV_Y) + { + switch (plat_joystick_state[joystick_nr].p[mapping & 3]) + { + case SDL_HAT_LEFTUP: case SDL_HAT_UP: case SDL_HAT_RIGHTUP: + return -32767; + + case SDL_HAT_LEFTDOWN: case SDL_HAT_DOWN: case SDL_HAT_RIGHTDOWN: + return 32767; + + default: + return 0; + } + } + else + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; +} +void joystick_process() +{ + int c, d; + + SDL_JoystickUpdate(); + for (c = 0; c < joysticks_present; c++) + { + int b; + + plat_joystick_state[c].a[0] = SDL_JoystickGetAxis(sdl_joy[c], 0); + plat_joystick_state[c].a[1] = SDL_JoystickGetAxis(sdl_joy[c], 1); + plat_joystick_state[c].a[2] = SDL_JoystickGetAxis(sdl_joy[c], 2); + plat_joystick_state[c].a[3] = SDL_JoystickGetAxis(sdl_joy[c], 3); + plat_joystick_state[c].a[4] = SDL_JoystickGetAxis(sdl_joy[c], 4); + plat_joystick_state[c].a[5] = SDL_JoystickGetAxis(sdl_joy[c], 5); + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = SDL_JoystickGetButton(sdl_joy[c], b); + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = SDL_JoystickGetHat(sdl_joy[c], b); + // pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + int x, y; + double angle, magnitude; + + x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); + y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); + magnitude = sqrt((double)x*(double)x + (double)y*(double)y); + + if (magnitude < 16384) + joystick_state[c].pov[d] = -1; + else + joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; + } + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + joystick_state[c].pov[d] = -1; + } + } +}