all repos — mgba @ 6248e44e47a8156555f5b9873a24093643a8a12f

mGBA Game Boy Advance Emulator

Qt: Remappable controls for tilt and gyroscope sensors
Jeffrey Pfau jeffrey@endrift.com
Tue, 21 Apr 2015 20:36:53 -0700
commit

6248e44e47a8156555f5b9873a24093643a8a12f

parent

3eb4c01515cc42f6f4cb35f0c8432b644fccf806

M CHANGESCHANGES

@@ -11,6 +11,7 @@ - Add "Step backwards" item for single increment rewind

- Deadzone estimation for game controllers - Analog inputs can be used for shortcuts - Menu items for specific solar sensor brightness levels + - Remappable controls for tilt and gyroscope sensors Bugfixes: - GBA: Fix timers not updating timing when writing to only the reload register - All: Fix sanitize-deb script not cleaning up after itself
M src/gba/input.csrc/gba/input.c

@@ -500,3 +500,23 @@ char deviceId[KEY_NAME_MAX];

snprintf(deviceId, sizeof(deviceId), "device%i", playerId); return ConfigurationSetValue(config, sectionName, deviceId, deviceName); } + +const char* GBAInputGetCustomValue(const struct Configuration* config, uint32_t type, const char* key, const char* profile) { + char sectionName[SECTION_NAME_MAX]; + if (profile) { + snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile); + } else { + _makeSectionName(sectionName, SECTION_NAME_MAX, type); + } + return ConfigurationGetValue(config, sectionName, key); +} + +void GBAInputSetCustomValue(struct Configuration* config, uint32_t type, const char* key, const char* value, const char* profile) { + char sectionName[SECTION_NAME_MAX]; + if (profile) { + snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile); + } else { + _makeSectionName(sectionName, SECTION_NAME_MAX, type); + } + ConfigurationSetValue(config, sectionName, key, value); +}
M src/gba/input.hsrc/gba/input.h

@@ -51,4 +51,7 @@

const char* GBAInputGetPreferredDevice(const struct Configuration*, uint32_t type, int playerId); void GBAInputSetPreferredDevice(struct Configuration*, uint32_t type, int playerId, const char* deviceName); +const char* GBAInputGetCustomValue(const struct Configuration* config, uint32_t type, const char* key, const char* profile); +void GBAInputSetCustomValue(struct Configuration* config, uint32_t type, const char* key, const char* value, const char* profile); + #endif
M src/platform/qt/InputController.cppsrc/platform/qt/InputController.cpp

@@ -110,6 +110,11 @@ }

void InputController::saveConfiguration(uint32_t type) { GBAInputMapSave(&m_inputMap, type, m_config->input()); +#ifdef BUILD_SDL + if (m_playerAttached) { + GBASDLPlayerSaveConfig(&m_sdlPlayer, m_config->input()); + } +#endif m_config->write(); }

@@ -169,6 +174,27 @@ }

GBARotationSource* InputController::rotationSource() { return &m_sdlPlayer.rotation.d; +} + +void InputController::registerTiltAxisX(int axis) { + m_sdlPlayer.rotation.axisX = axis; +} +void InputController::registerTiltAxisY(int axis) { + m_sdlPlayer.rotation.axisY = axis; +} +void InputController::registerGyroAxisX(int axis) { + m_sdlPlayer.rotation.gyroX = axis; +} +void InputController::registerGyroAxisY(int axis) { + m_sdlPlayer.rotation.gyroY = axis; +} + +float InputController::gyroSensitivity() const { + return m_sdlPlayer.rotation.gyroSensitivity; +} + +void InputController::setGyroSensitivity(float sensitivity) { + m_sdlPlayer.rotation.gyroSensitivity = sensitivity; } #else GBARumble* InputController::rumble() {
M src/platform/qt/InputController.hsrc/platform/qt/InputController.h

@@ -65,6 +65,14 @@ QStringList connectedGamepads(uint32_t type) const;

int gamepad(uint32_t type) const { return m_sdlPlayer.joystickIndex; } void setGamepad(uint32_t type, int index) { GBASDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); } void setPreferredGamepad(uint32_t type, const QString& device); + + void registerTiltAxisX(int axis); + void registerTiltAxisY(int axis); + void registerGyroAxisX(int axis); + void registerGyroAxisY(int axis); + + float gyroSensitivity() const; + void setGyroSensitivity(float sensitivity); #endif GBARumble* rumble();
M src/platform/qt/SensorView.cppsrc/platform/qt/SensorView.cpp

@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "SensorView.h" #include "GameController.h" +#include "GamepadAxisEvent.h" #include "InputController.h" using namespace QGBA;

@@ -50,6 +51,42 @@ m_ui.gyro->hide();

} else { m_timer.start(); } + + jiggerer(m_ui.tiltSetX, &InputController::registerTiltAxisX); + jiggerer(m_ui.tiltSetY, &InputController::registerTiltAxisY); + jiggerer(m_ui.gyroSetX, &InputController::registerGyroAxisX); + jiggerer(m_ui.gyroSetY, &InputController::registerGyroAxisY); + + m_ui.gyroSensitivity->setValue(m_input->gyroSensitivity() / 1e8f); + connect(m_ui.gyroSensitivity, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double value) { + m_input->setGyroSensitivity(value * 1e8f); + }); +} + +void SensorView::jiggerer(QAbstractButton* button, void (InputController::*setter)(int)) { + connect(button, &QAbstractButton::toggled, [this, button, setter](bool checked) { + if (!checked) { + m_jiggered = nullptr; + } else { + m_jiggered = [this, button, setter](int axis) { + (m_input->*setter)(axis); + button->setChecked(false); + }; + } + }); + button->installEventFilter(this); +} + +bool SensorView::eventFilter(QObject*, QEvent* event) { + if (event->type() == GamepadAxisEvent::Type()) { + GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event); + gae->accept(); + if (m_jiggered && gae->direction() != GamepadAxisEvent::NEUTRAL && gae->isNew()) { + m_jiggered(gae->axis()); + } + return true; + } + return false; } void SensorView::updateSensors() {
M src/platform/qt/SensorView.hsrc/platform/qt/SensorView.h

@@ -9,6 +9,8 @@

#include <QTimer> #include <QWidget> +#include <functional> + #include "ui_SensorView.h" struct GBARotationSource;

@@ -17,6 +19,7 @@ namespace QGBA {

class ConfigController; class GameController; +class GamepadAxisEvent; class InputController; class SensorView : public QWidget {

@@ -25,6 +28,9 @@

public: SensorView(GameController* controller, InputController* input, QWidget* parent = nullptr); +protected: + bool eventFilter(QObject*, QEvent* event) override; + private slots: void updateSensors(); void setLuminanceValue(int);

@@ -33,10 +39,13 @@

private: Ui::SensorView m_ui; + std::function<void(int)> m_jiggered; GameController* m_controller; InputController* m_input; GBARotationSource* m_rotation; QTimer m_timer; + + void jiggerer(QAbstractButton*, void (InputController::*)(int)); }; }
M src/platform/qt/SensorView.uisrc/platform/qt/SensorView.ui

@@ -6,8 +6,8 @@ <property name="geometry">

<rect> <x>0</x> <y>0</y> - <width>508</width> - <height>258</height> + <width>434</width> + <height>288</height> </rect> </property> <property name="sizePolicy">

@@ -157,12 +157,18 @@ <widget class="QPushButton" name="tiltSetY">

<property name="text"> <string>Set Y</string> </property> + <property name="checkable"> + <bool>true</bool> + </property> </widget> </item> <item row="0" column="0"> <widget class="QPushButton" name="tiltSetX"> <property name="text"> <string>Set X</string> + </property> + <property name="checkable"> + <bool>true</bool> </property> </widget> </item>

@@ -240,12 +246,18 @@ <widget class="QPushButton" name="gyroSetY">

<property name="text"> <string>Set Y</string> </property> + <property name="checkable"> + <bool>true</bool> + </property> </widget> </item> <item row="0" column="0"> <widget class="QPushButton" name="gyroSetX"> <property name="text"> <string>Set X</string> + </property> + <property name="checkable"> + <bool>true</bool> </property> </widget> </item>
M src/platform/sdl/sdl-events.csrc/platform/sdl/sdl-events.c

@@ -12,6 +12,7 @@ #include "gba/serialize.h"

#include "gba/video.h" #include "gba/renderers/video-software.h" #include "util/configuration.h" +#include "util/formatting.h" #include "util/vfs.h" #if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__)

@@ -233,10 +234,71 @@ GBAInputMapLoad(context->bindings, SDL_BINDING_KEY, config);

if (context->joystick) { GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config); #if SDL_VERSION_ATLEAST(2, 0, 0) - GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, SDL_JoystickName(context->joystick)); + const char* name = SDL_JoystickName(context->joystick); +#else + const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick)); +#endif + GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, name); + + const char* value; + char* end; + int axis; + value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisX", name); + if (value) { + axis = strtol(value, &end, 0); + if (end && !*end) { + context->rotation.axisX = axis; + } + } + value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisY", name); + if (value) { + axis = strtol(value, &end, 0); + if (end && !*end) { + context->rotation.axisY = axis; + } + } + value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisX", name); + if (value) { + axis = strtol(value, &end, 0); + if (end && !*end) { + context->rotation.gyroX = axis; + } + } + value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisY", name); + if (value) { + axis = strtol(value, &end, 0); + if (end && !*end) { + context->rotation.gyroY = axis; + } + } + value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "gyroSensitivity", name); + if (value) { + float sensitivity = strtof_u(value, &end); + if (end && !*end) { + context->rotation.gyroSensitivity = sensitivity; + } + } + } +} + +void GBASDLPlayerSaveConfig(const struct GBASDLPlayer* context, struct Configuration* config) { + if (context->joystick) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + const char* name = SDL_JoystickName(context->joystick); #else - GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, SDL_JoystickName(SDL_JoystickIndex(context->joystick))); + const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick)); #endif + char value[12]; + snprintf(value, sizeof(value), "%i", context->rotation.axisX); + GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisX", value, name); + snprintf(value, sizeof(value), "%i", context->rotation.axisY); + GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisY", value, name); + snprintf(value, sizeof(value), "%i", context->rotation.gyroX); + GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisX", value, name); + snprintf(value, sizeof(value), "%i", context->rotation.gyroY); + GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisY", value, name); + snprintf(value, sizeof(value), "%g", context->rotation.gyroSensitivity); + GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "gyroSensitivity", value, name); } }
M src/platform/sdl/sdl-events.hsrc/platform/sdl/sdl-events.h

@@ -78,6 +78,7 @@ void GBASDLPlayerChangeJoystick(struct GBASDLEvents*, struct GBASDLPlayer*, size_t index);

void GBASDLInitBindings(struct GBAInputMap* inputMap); void GBASDLPlayerLoadConfig(struct GBASDLPlayer*, const struct Configuration*); +void GBASDLPlayerSaveConfig(const struct GBASDLPlayer*, struct Configuration*); void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const union SDL_Event* event);