Skip to content

Commit

Permalink
android,ios: arcade vgamepad layout. android vgamepad rewrite
Browse files Browse the repository at this point in the history
Refactor common virtual gamepad code.
Distinct layouts for console and arcade.
Add arcade buttons 5 and 6, insert card button, service mode toggle.
System SP support
  • Loading branch information
flyinghead committed Dec 3, 2024
1 parent 78fa3ee commit 21f9e9f
Show file tree
Hide file tree
Showing 25 changed files with 3,399 additions and 1,118 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,8 @@ if(NOT LIBRETRO)
if(ANDROID OR IOS)
cmrc_add_resources(flycast-resources
WHENCE resources
resources/picture/buttons.png)
resources/picture/buttons.png
resources/picture/buttons-arcade.png)
endif()
endif()

Expand Down Expand Up @@ -1617,6 +1618,10 @@ if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
shell/android-studio/flycast/src/main/jni/src/Android.cpp
shell/android-studio/flycast/src/main/jni/src/android_gamepad.h
shell/android-studio/flycast/src/main/jni/src/android_storage.h
shell/android-studio/flycast/src/main/jni/src/http_client.h
shell/android-studio/flycast/src/main/jni/src/jni_util.h
shell/android-studio/flycast/src/main/jni/src/android_input.cpp
shell/android-studio/flycast/src/main/jni/src/android_keyboard.h)

target_link_libraries(${PROJECT_NAME} PRIVATE android log)
Expand Down
1 change: 1 addition & 0 deletions core/input/gamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum DreamcastKey
EMU_BTN_SAVESTATE,
EMU_BTN_BYPASS_KB,
EMU_BTN_SCREENSHOT,
EMU_BTN_SRVMODE, // used internally by virtual gamepad

// Real axes
DC_AXIS_TRIGGERS = 0x1000000,
Expand Down
117 changes: 117 additions & 0 deletions core/input/virtual_gamepad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
Copyright 2024 flyinghead
This file is part of Flycast.
Flycast 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 2 of the License, or
(at your option) any later version.
Flycast 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 Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "gamepad_device.h"
#include "ui/vgamepad.h"

class VirtualGamepad : public GamepadDevice
{
public:
VirtualGamepad(const char *api_name, int maple_port = 0)
: GamepadDevice(maple_port, api_name, false)
{
_name = "Virtual Gamepad";
_unique_id = "virtual_gamepad_uid";
input_mapper = std::make_shared<IdentityInputMapping>();
// hasAnalogStick = true; // TODO has an analog stick but input mapping isn't persisted

leftTrigger = DC_AXIS_LT;
rightTrigger = DC_AXIS_RT;
}

bool is_virtual_gamepad() override {
return true;
};

// normalized coordinates [-1, 1]
void joystickInput(float x, float y)
{
vgamepad::setAnalogStick(x, y);
int joyx = std::round(x * 32767.f);
int joyy = std::round(y * 32767.f);
if (joyx >= 0)
gamepad_axis_input(DC_AXIS_RIGHT, joyx);
else
gamepad_axis_input(DC_AXIS_LEFT, -joyx);
if (joyy >= 0)
gamepad_axis_input(DC_AXIS_DOWN, joyy);
else
gamepad_axis_input(DC_AXIS_UP, -joyy);
}

void releaseAll()
{
for (int i = 0; i < 32; i++)
if (buttonState & (1 << i))
gamepad_btn_input(1 << i, false);
buttonState = 0;
joystickInput(0, 0);
gamepad_axis_input(DC_AXIS_LT, 0);
gamepad_axis_input(DC_AXIS_RT, 0);
if (previousFastForward)
gamepad_btn_input(EMU_BTN_FFORWARD, false);
previousFastForward = false;
}

virtual bool handleButtonInput(u32& state, u32 key, bool pressed) {
// can be overridden in derived classes to handle specific key combos
// (iOS up+down or left+right)
return false;
}

void buttonInput(vgamepad::ControlId controlId, bool pressed)
{
u32 kcode = vgamepad::controlToDcKey(controlId);
if (kcode == 0)
return;
if (handleButtonInput(buttonState, kcode, pressed))
return;
if (kcode == DC_AXIS_LT) {
gamepad_axis_input(DC_AXIS_LT, pressed ? 0x7fff : 0);
}
else if (kcode == DC_AXIS_RT) {
gamepad_axis_input(DC_AXIS_RT, pressed ? 0x7fff : 0);
}
else if (kcode == EMU_BTN_SRVMODE) {
if (pressed)
vgamepad::toggleServiceMode();
}
else
{
if (pressed)
buttonState |= kcode;
else
buttonState &= ~kcode;
if ((kcode & (DC_DPAD_LEFT | DC_DPAD_RIGHT)) != 0
&& (kcode & (DC_DPAD_UP | DC_DPAD_DOWN)) != 0)
{
// diagonals
gamepad_btn_input(kcode & (DC_DPAD_LEFT | DC_DPAD_RIGHT), pressed);
gamepad_btn_input(kcode & (DC_DPAD_UP | DC_DPAD_DOWN), pressed);
}
else {
gamepad_btn_input(kcode, pressed);
}
}
}

private:
u32 buttonState = 0;
bool previousFastForward = false;
};
2 changes: 1 addition & 1 deletion core/ui/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1467,7 +1467,7 @@ static void gamepadSettingsPopup(const std::shared_ptr<GamepadDevice>& gamepad)

#if defined(__ANDROID__) || defined(TARGET_IPHONE)
vgamepad::ImguiVGamepadTexture tex;
ImGui::Image(tex.getId(), ScaledVec2(300, 112.5f), ImVec2(0, 1), ImVec2(1, 0.25f));
ImGui::Image(tex.getId(), ScaledVec2(300.f, 150.f), ImVec2(0, 1), ImVec2(1, 0));
#endif
const char *gamepadPngTitle = "Select a PNG file";
if (ImGui::Button("Choose Image...", ScaledVec2(150, 30)))
Expand Down
Loading

0 comments on commit 21f9e9f

Please sign in to comment.