Redesign the Input dialog (#1226)
This commit is contained in:
parent
737171c906
commit
796d603332
|
@ -9,7 +9,9 @@ melon_grc.h
|
||||||
melon.rc
|
melon.rc
|
||||||
cmake-build
|
cmake-build
|
||||||
cmake-build-debug
|
cmake-build-debug
|
||||||
|
compile_commands.json
|
||||||
.idea
|
.idea
|
||||||
|
.cache
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
|
|
@ -126,10 +126,14 @@ If everything went well, melonDS.app should now be in the current directory.
|
||||||
* limittox for the icon
|
* limittox for the icon
|
||||||
* All of you comrades who have been testing melonDS, reporting issues, suggesting shit, etc
|
* All of you comrades who have been testing melonDS, reporting issues, suggesting shit, etc
|
||||||
|
|
||||||
## License
|
## Licenses
|
||||||
|
|
||||||
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)
|
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
|
|
||||||
melonDS is free software: you can redistribute it and/or modify
|
melonDS is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
|
### External
|
||||||
|
* Images used in the Input Config Dialog - see `src/frontend/qt_sdl/InputConfig/resources/LICENSE.md`
|
||||||
|
|
|
@ -5,7 +5,9 @@ SET(SOURCES_QT_SDL
|
||||||
main_shaders.h
|
main_shaders.h
|
||||||
CheatsDialog.cpp
|
CheatsDialog.cpp
|
||||||
EmuSettingsDialog.cpp
|
EmuSettingsDialog.cpp
|
||||||
InputConfigDialog.cpp
|
InputConfig/InputConfigDialog.cpp
|
||||||
|
InputConfig/MapButton.h
|
||||||
|
InputConfig/resources/ds.qrc
|
||||||
VideoSettingsDialog.cpp
|
VideoSettingsDialog.cpp
|
||||||
AudioSettingsDialog.cpp
|
AudioSettingsDialog.cpp
|
||||||
WifiSettingsDialog.cpp
|
WifiSettingsDialog.cpp
|
||||||
|
@ -97,6 +99,7 @@ target_link_libraries(melonDS core)
|
||||||
|
|
||||||
if (BUILD_STATIC)
|
if (BUILD_STATIC)
|
||||||
target_link_libraries(melonDS -static ${SDL2_STATIC_LIBRARIES} ${SLIRP_STATIC_LIBRARIES} ${LIBARCHIVE_STATIC_LIBRARIES})
|
target_link_libraries(melonDS -static ${SDL2_STATIC_LIBRARIES} ${SLIRP_STATIC_LIBRARIES} ${LIBARCHIVE_STATIC_LIBRARIES})
|
||||||
|
qt_import_plugins(melonDS INCLUDE Qt::QSvgPlugin)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(melonDS ${SDL2_LIBRARIES} ${SLIRP_LIBRARIES} ${LIBARCHIVE_LIBRARIES})
|
target_link_libraries(melonDS ${SDL2_LIBRARIES} ${SLIRP_LIBRARIES} ${LIBARCHIVE_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2021 Arisotura
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "PlatformConfig.h"
|
||||||
|
|
||||||
|
#include "MapButton.h"
|
||||||
|
#include "Input.h"
|
||||||
|
#include "InputConfigDialog.h"
|
||||||
|
#include "ui_InputConfigDialog.h"
|
||||||
|
|
||||||
|
|
||||||
|
InputConfigDialog* InputConfigDialog::currentDlg = nullptr;
|
||||||
|
|
||||||
|
const int dskeyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 2, 3};
|
||||||
|
const char* dskeylabels[12] = {"A", "B", "X", "Y", "Left", "Right", "Up", "Down", "L", "R", "Select", "Start"};
|
||||||
|
|
||||||
|
const int hk_addons[] =
|
||||||
|
{
|
||||||
|
HK_SolarSensorIncrease,
|
||||||
|
HK_SolarSensorDecrease,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* hk_addons_labels[] =
|
||||||
|
{
|
||||||
|
"[Boktai] Sunlight + ",
|
||||||
|
"[Boktai] Sunlight - ",
|
||||||
|
};
|
||||||
|
|
||||||
|
const int hk_general[] =
|
||||||
|
{
|
||||||
|
HK_Pause,
|
||||||
|
HK_Reset,
|
||||||
|
HK_FrameStep,
|
||||||
|
HK_FastForward,
|
||||||
|
HK_FastForwardToggle,
|
||||||
|
HK_FullscreenToggle,
|
||||||
|
HK_Lid,
|
||||||
|
HK_Mic,
|
||||||
|
HK_SwapScreens
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* hk_general_labels[] =
|
||||||
|
{
|
||||||
|
"Pause/resume",
|
||||||
|
"Reset",
|
||||||
|
"Frame step",
|
||||||
|
"Fast forward",
|
||||||
|
"Toggle FPS limit",
|
||||||
|
"Toggle Fullscreen",
|
||||||
|
"Close/open lid",
|
||||||
|
"Microphone",
|
||||||
|
"Swap screens"
|
||||||
|
};
|
||||||
|
|
||||||
|
const int keypad_num = 12;
|
||||||
|
const int hk_addons_num = 2;
|
||||||
|
const int hk_general_num = 9;
|
||||||
|
|
||||||
|
|
||||||
|
InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new Ui::InputConfigDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
for (int i = 0; i < keypad_num; i++)
|
||||||
|
{
|
||||||
|
keypadKeyMap[i] = Config::KeyMapping[dskeyorder[i]];
|
||||||
|
keypadJoyMap[i] = Config::JoyMapping[dskeyorder[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < hk_addons_num; i++)
|
||||||
|
{
|
||||||
|
addonsKeyMap[i] = Config::HKKeyMapping[hk_addons[i]];
|
||||||
|
addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < hk_general_num; i++)
|
||||||
|
{
|
||||||
|
hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]];
|
||||||
|
hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
populatePage(ui->tabAddons, hk_addons_num, hk_addons_labels, addonsKeyMap, addonsJoyMap);
|
||||||
|
populatePage(ui->tabHotkeysGeneral, hk_general_num, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap);
|
||||||
|
|
||||||
|
int njoy = SDL_NumJoysticks();
|
||||||
|
if (njoy > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < njoy; i++)
|
||||||
|
{
|
||||||
|
const char* name = SDL_JoystickNameForIndex(i);
|
||||||
|
ui->cbxJoystick->addItem(QString(name));
|
||||||
|
}
|
||||||
|
ui->cbxJoystick->setCurrentIndex(Input::JoystickID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->cbxJoystick->addItem("(no joysticks available)");
|
||||||
|
ui->cbxJoystick->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupKeypadPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConfigDialog::~InputConfigDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::setupKeypadPage()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < keypad_num; i++)
|
||||||
|
{
|
||||||
|
QPushButton* pushButtonKey = this->findChild<QPushButton*>(QStringLiteral("btnKey") + dskeylabels[i]);
|
||||||
|
QPushButton* pushButtonJoy = this->findChild<QPushButton*>(QStringLiteral("btnJoy") + dskeylabels[i]);
|
||||||
|
|
||||||
|
KeyMapButton* keyMapButtonKey = new KeyMapButton(&keypadKeyMap[i], false);
|
||||||
|
JoyMapButton* keyMapButtonJoy = new JoyMapButton(&keypadJoyMap[i], false);
|
||||||
|
|
||||||
|
pushButtonKey->parentWidget()->layout()->replaceWidget(pushButtonKey, keyMapButtonKey);
|
||||||
|
pushButtonJoy->parentWidget()->layout()->replaceWidget(pushButtonJoy, keyMapButtonJoy);
|
||||||
|
|
||||||
|
delete pushButtonKey;
|
||||||
|
delete pushButtonJoy;
|
||||||
|
|
||||||
|
if (ui->cbxJoystick->isEnabled())
|
||||||
|
{
|
||||||
|
ui->stackMapping->setCurrentIndex(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap)
|
||||||
|
{
|
||||||
|
// kind of a hack
|
||||||
|
bool ishotkey = (page != ui->tabInput);
|
||||||
|
|
||||||
|
QHBoxLayout* main_layout = new QHBoxLayout();
|
||||||
|
|
||||||
|
QGroupBox* group;
|
||||||
|
QGridLayout* group_layout;
|
||||||
|
|
||||||
|
group = new QGroupBox("Keyboard mappings:");
|
||||||
|
main_layout->addWidget(group);
|
||||||
|
group_layout = new QGridLayout();
|
||||||
|
group_layout->setSpacing(1);
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
QLabel* label = new QLabel(QString(labels[i])+":");
|
||||||
|
KeyMapButton* btn = new KeyMapButton(&keymap[i], ishotkey);
|
||||||
|
|
||||||
|
group_layout->addWidget(label, i, 0);
|
||||||
|
group_layout->addWidget(btn, i, 1);
|
||||||
|
}
|
||||||
|
group_layout->setRowStretch(num, 1);
|
||||||
|
group->setLayout(group_layout);
|
||||||
|
group->setMinimumWidth(275);
|
||||||
|
|
||||||
|
group = new QGroupBox("Joystick mappings:");
|
||||||
|
main_layout->addWidget(group);
|
||||||
|
group_layout = new QGridLayout();
|
||||||
|
group_layout->setSpacing(1);
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
QLabel* label = new QLabel(QString(labels[i])+":");
|
||||||
|
JoyMapButton* btn = new JoyMapButton(&joymap[i], ishotkey);
|
||||||
|
|
||||||
|
group_layout->addWidget(label, i, 0);
|
||||||
|
group_layout->addWidget(btn, i, 1);
|
||||||
|
}
|
||||||
|
group_layout->setRowStretch(num, 1);
|
||||||
|
group->setLayout(group_layout);
|
||||||
|
group->setMinimumWidth(275);
|
||||||
|
|
||||||
|
page->setLayout(main_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::on_InputConfigDialog_accepted()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
Config::KeyMapping[dskeyorder[i]] = keypadKeyMap[i];
|
||||||
|
Config::JoyMapping[dskeyorder[i]] = keypadJoyMap[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
Config::HKKeyMapping[hk_addons[i]] = addonsKeyMap[i];
|
||||||
|
Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i];
|
||||||
|
Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::JoystickID = Input::JoystickID;
|
||||||
|
Config::Save();
|
||||||
|
|
||||||
|
closeDlg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::on_InputConfigDialog_rejected()
|
||||||
|
{
|
||||||
|
Input::JoystickID = Config::JoystickID;
|
||||||
|
Input::OpenJoystick();
|
||||||
|
|
||||||
|
closeDlg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::on_btnKeyMapSwitch_clicked()
|
||||||
|
{
|
||||||
|
ui->stackMapping->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::on_btnJoyMapSwitch_clicked()
|
||||||
|
{
|
||||||
|
ui->stackMapping->setCurrentIndex(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConfigDialog::on_cbxJoystick_currentIndexChanged(int id)
|
||||||
|
{
|
||||||
|
// prevent a spurious change
|
||||||
|
if (ui->cbxJoystick->count() < 2) return;
|
||||||
|
|
||||||
|
Input::JoystickID = id;
|
||||||
|
Input::OpenJoystick();
|
||||||
|
}
|
|
@ -55,10 +55,13 @@ private slots:
|
||||||
void on_InputConfigDialog_accepted();
|
void on_InputConfigDialog_accepted();
|
||||||
void on_InputConfigDialog_rejected();
|
void on_InputConfigDialog_rejected();
|
||||||
|
|
||||||
|
void on_btnKeyMapSwitch_clicked();
|
||||||
|
void on_btnJoyMapSwitch_clicked();
|
||||||
void on_cbxJoystick_currentIndexChanged(int id);
|
void on_cbxJoystick_currentIndexChanged(int id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap);
|
void populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap);
|
||||||
|
void setupKeypadPage();
|
||||||
|
|
||||||
Ui::InputConfigDialog* ui;
|
Ui::InputConfigDialog* ui;
|
||||||
|
|
||||||
|
@ -68,56 +71,4 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class KeyMapButton : public QPushButton
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit KeyMapButton(int* mapping, bool hotkey);
|
|
||||||
~KeyMapButton();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void keyPressEvent(QKeyEvent* event) override;
|
|
||||||
void focusOutEvent(QFocusEvent* event) override;
|
|
||||||
|
|
||||||
bool focusNextPrevChild(bool next) override { return false; }
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onClick();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString mappingText();
|
|
||||||
|
|
||||||
int* mapping;
|
|
||||||
bool isHotkey;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JoyMapButton : public QPushButton
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit JoyMapButton(int* mapping, bool hotkey);
|
|
||||||
~JoyMapButton();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void keyPressEvent(QKeyEvent* event) override;
|
|
||||||
void focusOutEvent(QFocusEvent* event) override;
|
|
||||||
void timerEvent(QTimerEvent* event) override;
|
|
||||||
|
|
||||||
bool focusNextPrevChild(bool next) override { return false; }
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onClick();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString mappingText();
|
|
||||||
|
|
||||||
int* mapping;
|
|
||||||
bool isHotkey;
|
|
||||||
|
|
||||||
int timerID;
|
|
||||||
int axesRest[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INPUTCONFIGDIALOG_H
|
#endif // INPUTCONFIGDIALOG_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,355 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016-2021 Arisotura
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAPBUTTON_H
|
||||||
|
#define MAPBUTTON_H
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include "Input.h"
|
||||||
|
|
||||||
|
class KeyMapButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeyMapButton(int* mapping, bool hotkey) : QPushButton()
|
||||||
|
{
|
||||||
|
this->mapping = mapping;
|
||||||
|
this->isHotkey = hotkey;
|
||||||
|
|
||||||
|
setCheckable(true);
|
||||||
|
setText(mappingText());
|
||||||
|
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
|
||||||
|
|
||||||
|
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
~KeyMapButton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent* event) override
|
||||||
|
{
|
||||||
|
if (!isChecked()) return QPushButton::keyPressEvent(event);
|
||||||
|
|
||||||
|
printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), (int)event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode());
|
||||||
|
|
||||||
|
int key = event->key();
|
||||||
|
int mod = event->modifiers();
|
||||||
|
bool ismod = (key == Qt::Key_Control ||
|
||||||
|
key == Qt::Key_Alt ||
|
||||||
|
key == Qt::Key_AltGr ||
|
||||||
|
key == Qt::Key_Shift ||
|
||||||
|
key == Qt::Key_Meta);
|
||||||
|
|
||||||
|
if (!mod)
|
||||||
|
{
|
||||||
|
if (key == Qt::Key_Escape) { click(); return; }
|
||||||
|
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHotkey)
|
||||||
|
{
|
||||||
|
if (ismod)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ismod)
|
||||||
|
key |= mod;
|
||||||
|
else if (Input::IsRightModKey(event))
|
||||||
|
key |= (1<<31);
|
||||||
|
|
||||||
|
*mapping = key;
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
|
||||||
|
void focusOutEvent(QFocusEvent* event) override
|
||||||
|
{
|
||||||
|
if (isChecked())
|
||||||
|
{
|
||||||
|
// if we lost the focus while mapping, consider it 'done'
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton::focusOutEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool focusNextPrevChild(bool next) override { return false; }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onClick()
|
||||||
|
{
|
||||||
|
if (isChecked())
|
||||||
|
{
|
||||||
|
setText("[press key]");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setText(mappingText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString mappingText()
|
||||||
|
{
|
||||||
|
int key = *mapping;
|
||||||
|
|
||||||
|
if (key == -1) return "None";
|
||||||
|
|
||||||
|
QString isright = (key & (1<<31)) ? "Right " : "Left ";
|
||||||
|
key &= ~(1<<31);
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case Qt::Key_Control: return isright + "Ctrl";
|
||||||
|
case Qt::Key_Alt: return "Alt";
|
||||||
|
case Qt::Key_AltGr: return "AltGr";
|
||||||
|
case Qt::Key_Shift: return isright + "Shift";
|
||||||
|
case Qt::Key_Meta: return "Meta";
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case Qt::Key_Control: return isright + "⌘";
|
||||||
|
case Qt::Key_Alt: return isright + "⌥";
|
||||||
|
case Qt::Key_Shift: return isright + "⇧";
|
||||||
|
case Qt::Key_Meta: return isright + "⌃";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QKeySequence seq(key);
|
||||||
|
QString ret = seq.toString(QKeySequence::NativeText);
|
||||||
|
|
||||||
|
// weak attempt at detecting garbage key names
|
||||||
|
//if (ret.length() == 2 && ret[0].unicode() > 0xFF)
|
||||||
|
// return QString("[%1]").arg(key, 8, 16);
|
||||||
|
|
||||||
|
return ret.replace("&", "&&");
|
||||||
|
}
|
||||||
|
|
||||||
|
int* mapping;
|
||||||
|
bool isHotkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JoyMapButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
JoyMapButton(int* mapping, bool hotkey) : QPushButton()
|
||||||
|
{
|
||||||
|
this->mapping = mapping;
|
||||||
|
this->isHotkey = hotkey;
|
||||||
|
|
||||||
|
setCheckable(true);
|
||||||
|
setText(mappingText());
|
||||||
|
|
||||||
|
connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick);
|
||||||
|
|
||||||
|
timerID = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~JoyMapButton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent* event) override
|
||||||
|
{
|
||||||
|
if (!isChecked()) return QPushButton::keyPressEvent(event);
|
||||||
|
|
||||||
|
int key = event->key();
|
||||||
|
int mod = event->modifiers();
|
||||||
|
|
||||||
|
if (!mod)
|
||||||
|
{
|
||||||
|
if (key == Qt::Key_Escape) { click(); return; }
|
||||||
|
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void focusOutEvent(QFocusEvent* event) override
|
||||||
|
{
|
||||||
|
if (isChecked())
|
||||||
|
{
|
||||||
|
// if we lost the focus while mapping, consider it 'done'
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton::focusOutEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timerEvent(QTimerEvent* event) override
|
||||||
|
{
|
||||||
|
SDL_Joystick* joy = Input::Joystick;
|
||||||
|
if (!joy) { click(); return; }
|
||||||
|
if (!SDL_JoystickGetAttached(joy)) { click(); return; }
|
||||||
|
|
||||||
|
int oldmap;
|
||||||
|
if (*mapping == -1) oldmap = 0xFFFF;
|
||||||
|
else oldmap = *mapping;
|
||||||
|
|
||||||
|
int nbuttons = SDL_JoystickNumButtons(joy);
|
||||||
|
for (int i = 0; i < nbuttons; i++)
|
||||||
|
{
|
||||||
|
if (SDL_JoystickGetButton(joy, i))
|
||||||
|
{
|
||||||
|
*mapping = (oldmap & 0xFFFF0000) | i;
|
||||||
|
click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nhats = SDL_JoystickNumHats(joy);
|
||||||
|
if (nhats > 16) nhats = 16;
|
||||||
|
for (int i = 0; i < nhats; i++)
|
||||||
|
{
|
||||||
|
Uint8 blackhat = SDL_JoystickGetHat(joy, i);
|
||||||
|
if (blackhat)
|
||||||
|
{
|
||||||
|
if (blackhat & 0x1) blackhat = 0x1;
|
||||||
|
else if (blackhat & 0x2) blackhat = 0x2;
|
||||||
|
else if (blackhat & 0x4) blackhat = 0x4;
|
||||||
|
else blackhat = 0x8;
|
||||||
|
|
||||||
|
*mapping = (oldmap & 0xFFFF0000) | 0x100 | blackhat | (i << 4);
|
||||||
|
click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int naxes = SDL_JoystickNumAxes(joy);
|
||||||
|
if (naxes > 16) naxes = 16;
|
||||||
|
for (int i = 0; i < naxes; i++)
|
||||||
|
{
|
||||||
|
Sint16 axisval = SDL_JoystickGetAxis(joy, i);
|
||||||
|
int diff = abs(axisval - axesRest[i]);
|
||||||
|
|
||||||
|
if (axesRest[i] < -16384 && axisval >= 0)
|
||||||
|
{
|
||||||
|
*mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24);
|
||||||
|
click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (diff > 16384)
|
||||||
|
{
|
||||||
|
int axistype;
|
||||||
|
if (axisval > 0) axistype = 0;
|
||||||
|
else axistype = 1;
|
||||||
|
|
||||||
|
*mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24);
|
||||||
|
click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool focusNextPrevChild(bool next) override { return false; }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onClick()
|
||||||
|
{
|
||||||
|
if (isChecked())
|
||||||
|
{
|
||||||
|
setText("[press button/axis]");
|
||||||
|
timerID = startTimer(50);
|
||||||
|
|
||||||
|
memset(axesRest, 0, sizeof(axesRest));
|
||||||
|
if (Input::Joystick && SDL_JoystickGetAttached(Input::Joystick))
|
||||||
|
{
|
||||||
|
int naxes = SDL_JoystickNumAxes(Input::Joystick);
|
||||||
|
if (naxes > 16) naxes = 16;
|
||||||
|
for (int a = 0; a < naxes; a++)
|
||||||
|
{
|
||||||
|
axesRest[a] = SDL_JoystickGetAxis(Input::Joystick, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setText(mappingText());
|
||||||
|
if (timerID) { killTimer(timerID); timerID = 0; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString mappingText()
|
||||||
|
{
|
||||||
|
int id = *mapping;
|
||||||
|
|
||||||
|
if (id == -1) return "None";
|
||||||
|
|
||||||
|
bool hasbtn = ((id & 0xFFFF) != 0xFFFF);
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
if (hasbtn)
|
||||||
|
{
|
||||||
|
if (id & 0x100)
|
||||||
|
{
|
||||||
|
int hatnum = ((id >> 4) & 0xF) + 1;
|
||||||
|
|
||||||
|
switch (id & 0xF)
|
||||||
|
{
|
||||||
|
case 0x1: str = "Hat %1 up"; break;
|
||||||
|
case 0x2: str = "Hat %1 right"; break;
|
||||||
|
case 0x4: str = "Hat %1 down"; break;
|
||||||
|
case 0x8: str = "Hat %1 left"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str.arg(hatnum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str = QString("Button %1").arg((id & 0xFFFF) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id & 0x10000)
|
||||||
|
{
|
||||||
|
int axisnum = ((id >> 24) & 0xF) + 1;
|
||||||
|
|
||||||
|
if (hasbtn) str += " / ";
|
||||||
|
|
||||||
|
switch ((id >> 20) & 0xF)
|
||||||
|
{
|
||||||
|
case 0: str += QString("Axis %1 +").arg(axisnum); break;
|
||||||
|
case 1: str += QString("Axis %1 -").arg(axisnum); break;
|
||||||
|
case 2: str += QString("Trigger %1").arg(axisnum); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int* mapping;
|
||||||
|
bool isHotkey;
|
||||||
|
|
||||||
|
int timerID;
|
||||||
|
int axesRest[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAPBUTTON_H
|
|
@ -0,0 +1,6 @@
|
||||||
|
These vector images are modified from the [Nintendo DS Lite illustration on dimensions.com](https://www.dimensions.com/element/nintendo-ds-lite).
|
||||||
|
|
||||||
|
These have been used with the permission of the copyright holders.
|
||||||
|
> "We restrict the usage of our drawings and 3D models in commercial software, but as long as it's a free and open source community project, that would be approved. Any reference/backlink to Dimensions.com that could be provided in the developer notes and/or credits for the project would be sufficient for use."
|
||||||
|
|
||||||
|
https://www.dimensions.com/legal
|
|
@ -0,0 +1,6 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="ds">
|
||||||
|
<file>ds_open.svg</file>
|
||||||
|
<file>ds_back.svg</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 30 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 102 KiB |
|
@ -1,511 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2016-2021 Arisotura
|
|
||||||
|
|
||||||
This file is part of melonDS.
|
|
||||||
|
|
||||||
melonDS is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
any later version.
|
|
||||||
|
|
||||||
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QGroupBox>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QKeyEvent>
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "Config.h"
|
|
||||||
#include "PlatformConfig.h"
|
|
||||||
|
|
||||||
#include "Input.h"
|
|
||||||
#include "InputConfigDialog.h"
|
|
||||||
#include "ui_InputConfigDialog.h"
|
|
||||||
|
|
||||||
|
|
||||||
InputConfigDialog* InputConfigDialog::currentDlg = nullptr;
|
|
||||||
|
|
||||||
const int dskeyorder[12] = {0, 1, 10, 11, 5, 4, 6, 7, 9, 8, 2, 3};
|
|
||||||
const char* dskeylabels[12] = {"A", "B", "X", "Y", "Left", "Right", "Up", "Down", "L", "R", "Select", "Start"};
|
|
||||||
|
|
||||||
const int hk_addons[] =
|
|
||||||
{
|
|
||||||
HK_SolarSensorIncrease,
|
|
||||||
HK_SolarSensorDecrease,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* hk_addons_labels[] =
|
|
||||||
{
|
|
||||||
"[Boktai] Sunlight + ",
|
|
||||||
"[Boktai] Sunlight - ",
|
|
||||||
};
|
|
||||||
|
|
||||||
const int hk_general[] =
|
|
||||||
{
|
|
||||||
HK_Pause,
|
|
||||||
HK_Reset,
|
|
||||||
HK_FrameStep,
|
|
||||||
HK_FastForward,
|
|
||||||
HK_FastForwardToggle,
|
|
||||||
HK_FullscreenToggle,
|
|
||||||
HK_Lid,
|
|
||||||
HK_Mic,
|
|
||||||
HK_SwapScreens
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* hk_general_labels[] =
|
|
||||||
{
|
|
||||||
"Pause/resume",
|
|
||||||
"Reset",
|
|
||||||
"Frame step",
|
|
||||||
"Fast forward",
|
|
||||||
"Toggle FPS limit",
|
|
||||||
"Toggle Fullscreen",
|
|
||||||
"Close/open lid",
|
|
||||||
"Microphone",
|
|
||||||
"Swap screens"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
InputConfigDialog::InputConfigDialog(QWidget* parent) : QDialog(parent), ui(new Ui::InputConfigDialog)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
|
|
||||||
for (int i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
keypadKeyMap[i] = Config::KeyMapping[dskeyorder[i]];
|
|
||||||
keypadJoyMap[i] = Config::JoyMapping[dskeyorder[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
addonsKeyMap[i] = Config::HKKeyMapping[hk_addons[i]];
|
|
||||||
addonsJoyMap[i] = Config::HKJoyMapping[hk_addons[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++)
|
|
||||||
{
|
|
||||||
hkGeneralKeyMap[i] = Config::HKKeyMapping[hk_general[i]];
|
|
||||||
hkGeneralJoyMap[i] = Config::HKJoyMapping[hk_general[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
populatePage(ui->tabInput, 12, dskeylabels, keypadKeyMap, keypadJoyMap);
|
|
||||||
populatePage(ui->tabAddons, 2, hk_addons_labels, addonsKeyMap, addonsJoyMap);
|
|
||||||
populatePage(ui->tabHotkeysGeneral, 9, hk_general_labels, hkGeneralKeyMap, hkGeneralJoyMap);
|
|
||||||
|
|
||||||
int njoy = SDL_NumJoysticks();
|
|
||||||
if (njoy > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < njoy; i++)
|
|
||||||
{
|
|
||||||
const char* name = SDL_JoystickNameForIndex(i);
|
|
||||||
ui->cbxJoystick->addItem(QString(name));
|
|
||||||
}
|
|
||||||
ui->cbxJoystick->setCurrentIndex(Input::JoystickID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ui->cbxJoystick->addItem("(no joysticks available)");
|
|
||||||
ui->cbxJoystick->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InputConfigDialog::~InputConfigDialog()
|
|
||||||
{
|
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputConfigDialog::populatePage(QWidget* page, int num, const char** labels, int* keymap, int* joymap)
|
|
||||||
{
|
|
||||||
// kind of a hack
|
|
||||||
bool ishotkey = (page != ui->tabInput);
|
|
||||||
|
|
||||||
QHBoxLayout* main_layout = new QHBoxLayout();
|
|
||||||
|
|
||||||
QGroupBox* group;
|
|
||||||
QGridLayout* group_layout;
|
|
||||||
|
|
||||||
group = new QGroupBox("Keyboard mappings:");
|
|
||||||
main_layout->addWidget(group);
|
|
||||||
group_layout = new QGridLayout();
|
|
||||||
group_layout->setSpacing(1);
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
QLabel* label = new QLabel(QString(labels[i])+":");
|
|
||||||
KeyMapButton* btn = new KeyMapButton(&keymap[i], ishotkey);
|
|
||||||
|
|
||||||
group_layout->addWidget(label, i, 0);
|
|
||||||
group_layout->addWidget(btn, i, 1);
|
|
||||||
}
|
|
||||||
group_layout->setRowStretch(num, 1);
|
|
||||||
group->setLayout(group_layout);
|
|
||||||
group->setMinimumWidth(275);
|
|
||||||
|
|
||||||
group = new QGroupBox("Joystick mappings:");
|
|
||||||
main_layout->addWidget(group);
|
|
||||||
group_layout = new QGridLayout();
|
|
||||||
group_layout->setSpacing(1);
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
QLabel* label = new QLabel(QString(labels[i])+":");
|
|
||||||
JoyMapButton* btn = new JoyMapButton(&joymap[i], ishotkey);
|
|
||||||
|
|
||||||
group_layout->addWidget(label, i, 0);
|
|
||||||
group_layout->addWidget(btn, i, 1);
|
|
||||||
}
|
|
||||||
group_layout->setRowStretch(num, 1);
|
|
||||||
group->setLayout(group_layout);
|
|
||||||
group->setMinimumWidth(275);
|
|
||||||
|
|
||||||
page->setLayout(main_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputConfigDialog::on_InputConfigDialog_accepted()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
Config::KeyMapping[dskeyorder[i]] = keypadKeyMap[i];
|
|
||||||
Config::JoyMapping[dskeyorder[i]] = keypadJoyMap[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
Config::HKKeyMapping[hk_addons[i]] = addonsKeyMap[i];
|
|
||||||
Config::HKJoyMapping[hk_addons[i]] = addonsJoyMap[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++)
|
|
||||||
{
|
|
||||||
Config::HKKeyMapping[hk_general[i]] = hkGeneralKeyMap[i];
|
|
||||||
Config::HKJoyMapping[hk_general[i]] = hkGeneralJoyMap[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Config::JoystickID = Input::JoystickID;
|
|
||||||
Config::Save();
|
|
||||||
|
|
||||||
closeDlg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputConfigDialog::on_InputConfigDialog_rejected()
|
|
||||||
{
|
|
||||||
Input::JoystickID = Config::JoystickID;
|
|
||||||
Input::OpenJoystick();
|
|
||||||
|
|
||||||
closeDlg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputConfigDialog::on_cbxJoystick_currentIndexChanged(int id)
|
|
||||||
{
|
|
||||||
// prevent a spurious change
|
|
||||||
if (ui->cbxJoystick->count() < 2) return;
|
|
||||||
|
|
||||||
Input::JoystickID = id;
|
|
||||||
Input::OpenJoystick();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
KeyMapButton::KeyMapButton(int* mapping, bool hotkey) : QPushButton()
|
|
||||||
{
|
|
||||||
this->mapping = mapping;
|
|
||||||
this->isHotkey = hotkey;
|
|
||||||
|
|
||||||
setCheckable(true);
|
|
||||||
setText(mappingText());
|
|
||||||
setFocusPolicy(Qt::StrongFocus); //Fixes binding keys in macOS
|
|
||||||
|
|
||||||
connect(this, &KeyMapButton::clicked, this, &KeyMapButton::onClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyMapButton::~KeyMapButton()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyMapButton::keyPressEvent(QKeyEvent* event)
|
|
||||||
{
|
|
||||||
if (!isChecked()) return QPushButton::keyPressEvent(event);
|
|
||||||
|
|
||||||
printf("KEY PRESSED = %08X %08X | %08X %08X %08X\n", event->key(), (int)event->modifiers(), event->nativeVirtualKey(), event->nativeModifiers(), event->nativeScanCode());
|
|
||||||
|
|
||||||
int key = event->key();
|
|
||||||
int mod = event->modifiers();
|
|
||||||
bool ismod = (key == Qt::Key_Control ||
|
|
||||||
key == Qt::Key_Alt ||
|
|
||||||
key == Qt::Key_AltGr ||
|
|
||||||
key == Qt::Key_Shift ||
|
|
||||||
key == Qt::Key_Meta);
|
|
||||||
|
|
||||||
if (!mod)
|
|
||||||
{
|
|
||||||
if (key == Qt::Key_Escape) { click(); return; }
|
|
||||||
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isHotkey)
|
|
||||||
{
|
|
||||||
if (ismod)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ismod)
|
|
||||||
key |= mod;
|
|
||||||
else if (Input::IsRightModKey(event))
|
|
||||||
key |= (1<<31);
|
|
||||||
|
|
||||||
*mapping = key;
|
|
||||||
click();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyMapButton::focusOutEvent(QFocusEvent* event)
|
|
||||||
{
|
|
||||||
if (isChecked())
|
|
||||||
{
|
|
||||||
// if we lost the focus while mapping, consider it 'done'
|
|
||||||
click();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton::focusOutEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyMapButton::onClick()
|
|
||||||
{
|
|
||||||
if (isChecked())
|
|
||||||
{
|
|
||||||
setText("[press key]");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setText(mappingText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString KeyMapButton::mappingText()
|
|
||||||
{
|
|
||||||
int key = *mapping;
|
|
||||||
|
|
||||||
if (key == -1) return "None";
|
|
||||||
|
|
||||||
QString isright = (key & (1<<31)) ? "Right " : "Left ";
|
|
||||||
key &= ~(1<<31);
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Qt::Key_Control: return isright + "Ctrl";
|
|
||||||
case Qt::Key_Alt: return "Alt";
|
|
||||||
case Qt::Key_AltGr: return "AltGr";
|
|
||||||
case Qt::Key_Shift: return isright + "Shift";
|
|
||||||
case Qt::Key_Meta: return "Meta";
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case Qt::Key_Control: return isright + "⌘";
|
|
||||||
case Qt::Key_Alt: return isright + "⌥";
|
|
||||||
case Qt::Key_Shift: return isright + "⇧";
|
|
||||||
case Qt::Key_Meta: return isright + "⌃";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QKeySequence seq(key);
|
|
||||||
QString ret = seq.toString(QKeySequence::NativeText);
|
|
||||||
|
|
||||||
// weak attempt at detecting garbage key names
|
|
||||||
//if (ret.length() == 2 && ret[0].unicode() > 0xFF)
|
|
||||||
// return QString("[%1]").arg(key, 8, 16);
|
|
||||||
|
|
||||||
return ret.replace("&", "&&");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JoyMapButton::JoyMapButton(int* mapping, bool hotkey) : QPushButton()
|
|
||||||
{
|
|
||||||
this->mapping = mapping;
|
|
||||||
this->isHotkey = hotkey;
|
|
||||||
|
|
||||||
setCheckable(true);
|
|
||||||
setText(mappingText());
|
|
||||||
|
|
||||||
connect(this, &JoyMapButton::clicked, this, &JoyMapButton::onClick);
|
|
||||||
|
|
||||||
timerID = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JoyMapButton::~JoyMapButton()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoyMapButton::keyPressEvent(QKeyEvent* event)
|
|
||||||
{
|
|
||||||
if (!isChecked()) return QPushButton::keyPressEvent(event);
|
|
||||||
|
|
||||||
int key = event->key();
|
|
||||||
int mod = event->modifiers();
|
|
||||||
|
|
||||||
if (!mod)
|
|
||||||
{
|
|
||||||
if (key == Qt::Key_Escape) { click(); return; }
|
|
||||||
if (key == Qt::Key_Backspace) { *mapping = -1; click(); return; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoyMapButton::focusOutEvent(QFocusEvent* event)
|
|
||||||
{
|
|
||||||
if (isChecked())
|
|
||||||
{
|
|
||||||
// if we lost the focus while mapping, consider it 'done'
|
|
||||||
click();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton::focusOutEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoyMapButton::timerEvent(QTimerEvent* event)
|
|
||||||
{
|
|
||||||
SDL_Joystick* joy = Input::Joystick;
|
|
||||||
if (!joy) { click(); return; }
|
|
||||||
if (!SDL_JoystickGetAttached(joy)) { click(); return; }
|
|
||||||
|
|
||||||
int oldmap;
|
|
||||||
if (*mapping == -1) oldmap = 0xFFFF;
|
|
||||||
else oldmap = *mapping;
|
|
||||||
|
|
||||||
int nbuttons = SDL_JoystickNumButtons(joy);
|
|
||||||
for (int i = 0; i < nbuttons; i++)
|
|
||||||
{
|
|
||||||
if (SDL_JoystickGetButton(joy, i))
|
|
||||||
{
|
|
||||||
*mapping = (oldmap & 0xFFFF0000) | i;
|
|
||||||
click();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int nhats = SDL_JoystickNumHats(joy);
|
|
||||||
if (nhats > 16) nhats = 16;
|
|
||||||
for (int i = 0; i < nhats; i++)
|
|
||||||
{
|
|
||||||
Uint8 blackhat = SDL_JoystickGetHat(joy, i);
|
|
||||||
if (blackhat)
|
|
||||||
{
|
|
||||||
if (blackhat & 0x1) blackhat = 0x1;
|
|
||||||
else if (blackhat & 0x2) blackhat = 0x2;
|
|
||||||
else if (blackhat & 0x4) blackhat = 0x4;
|
|
||||||
else blackhat = 0x8;
|
|
||||||
|
|
||||||
*mapping = (oldmap & 0xFFFF0000) | 0x100 | blackhat | (i << 4);
|
|
||||||
click();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int naxes = SDL_JoystickNumAxes(joy);
|
|
||||||
if (naxes > 16) naxes = 16;
|
|
||||||
for (int i = 0; i < naxes; i++)
|
|
||||||
{
|
|
||||||
Sint16 axisval = SDL_JoystickGetAxis(joy, i);
|
|
||||||
int diff = abs(axisval - axesRest[i]);
|
|
||||||
|
|
||||||
if (axesRest[i] < -16384 && axisval >= 0)
|
|
||||||
{
|
|
||||||
*mapping = (oldmap & 0xFFFF) | 0x10000 | (2 << 20) | (i << 24);
|
|
||||||
click();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (diff > 16384)
|
|
||||||
{
|
|
||||||
int axistype;
|
|
||||||
if (axisval > 0) axistype = 0;
|
|
||||||
else axistype = 1;
|
|
||||||
|
|
||||||
*mapping = (oldmap & 0xFFFF) | 0x10000 | (axistype << 20) | (i << 24);
|
|
||||||
click();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoyMapButton::onClick()
|
|
||||||
{
|
|
||||||
if (isChecked())
|
|
||||||
{
|
|
||||||
setText("[press button/axis]");
|
|
||||||
timerID = startTimer(50);
|
|
||||||
|
|
||||||
memset(axesRest, 0, sizeof(axesRest));
|
|
||||||
if (Input::Joystick && SDL_JoystickGetAttached(Input::Joystick))
|
|
||||||
{
|
|
||||||
int naxes = SDL_JoystickNumAxes(Input::Joystick);
|
|
||||||
if (naxes > 16) naxes = 16;
|
|
||||||
for (int a = 0; a < naxes; a++)
|
|
||||||
{
|
|
||||||
axesRest[a] = SDL_JoystickGetAxis(Input::Joystick, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setText(mappingText());
|
|
||||||
if (timerID) { killTimer(timerID); timerID = 0; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString JoyMapButton::mappingText()
|
|
||||||
{
|
|
||||||
int id = *mapping;
|
|
||||||
|
|
||||||
if (id == -1) return "None";
|
|
||||||
|
|
||||||
bool hasbtn = ((id & 0xFFFF) != 0xFFFF);
|
|
||||||
QString str;
|
|
||||||
|
|
||||||
if (hasbtn)
|
|
||||||
{
|
|
||||||
if (id & 0x100)
|
|
||||||
{
|
|
||||||
int hatnum = ((id >> 4) & 0xF) + 1;
|
|
||||||
|
|
||||||
switch (id & 0xF)
|
|
||||||
{
|
|
||||||
case 0x1: str = "Hat %1 up"; break;
|
|
||||||
case 0x2: str = "Hat %1 right"; break;
|
|
||||||
case 0x4: str = "Hat %1 down"; break;
|
|
||||||
case 0x8: str = "Hat %1 left"; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = str.arg(hatnum);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str = QString("Button %1").arg((id & 0xFFFF) + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id & 0x10000)
|
|
||||||
{
|
|
||||||
int axisnum = ((id >> 24) & 0xF) + 1;
|
|
||||||
|
|
||||||
if (hasbtn) str += " / ";
|
|
||||||
|
|
||||||
switch ((id >> 20) & 0xF)
|
|
||||||
{
|
|
||||||
case 0: str += QString("Axis %1 +").arg(axisnum); break;
|
|
||||||
case 1: str += QString("Axis %1 -").arg(axisnum); break;
|
|
||||||
case 2: str += QString("Trigger %1").arg(axisnum); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>InputConfigDialog</class>
|
|
||||||
<widget class="QDialog" name="InputConfigDialog">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>488</width>
|
|
||||||
<height>365</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Input and hotkeys - melonDS</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<property name="sizeConstraint">
|
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="tabInput">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>DS keypad</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="tabAddons">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Add-ons</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="tabHotkeysGeneral">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>General hotkeys</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Joystick:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="cbxJoystick">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string><html><head/><body><p>Selects which joystick will be used for joystick input, if any is present.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>InputConfigDialog</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>248</x>
|
|
||||||
<y>254</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>157</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>rejected()</signal>
|
|
||||||
<receiver>InputConfigDialog</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>316</x>
|
|
||||||
<y>260</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>286</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
|
@ -52,7 +52,7 @@
|
||||||
#include "Input.h"
|
#include "Input.h"
|
||||||
#include "CheatsDialog.h"
|
#include "CheatsDialog.h"
|
||||||
#include "EmuSettingsDialog.h"
|
#include "EmuSettingsDialog.h"
|
||||||
#include "InputConfigDialog.h"
|
#include "InputConfig/InputConfigDialog.h"
|
||||||
#include "VideoSettingsDialog.h"
|
#include "VideoSettingsDialog.h"
|
||||||
#include "AudioSettingsDialog.h"
|
#include "AudioSettingsDialog.h"
|
||||||
#include "WifiSettingsDialog.h"
|
#include "WifiSettingsDialog.h"
|
||||||
|
|
|
@ -203,7 +203,7 @@ fixup_libs(executable, executable)
|
||||||
|
|
||||||
bundle_plugins = File.join($bundle, "Contents", "PlugIns")
|
bundle_plugins = File.join($bundle, "Contents", "PlugIns")
|
||||||
|
|
||||||
want_plugins = ["styles/libqmacstyle.dylib", "platforms/libqcocoa.dylib"]
|
want_plugins = ["styles/libqmacstyle.dylib", "platforms/libqcocoa.dylib", "imageformats/libqsvg.dylib"]
|
||||||
want_plugins.each do |plug|
|
want_plugins.each do |plug|
|
||||||
destdir = File.join(bundle_plugins, File.dirname(plug))
|
destdir = File.join(bundle_plugins, File.dirname(plug))
|
||||||
FileUtils.mkdir_p(destdir)
|
FileUtils.mkdir_p(destdir)
|
||||||
|
|
Loading…
Reference in New Issue