mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Merge pull request #21248 from hrydgard/control-mapper-refactor
Control mapper refactor, allow unpausing using analog triggers if mapped
This commit is contained in:
+52
-32
@@ -18,6 +18,7 @@ using KeyMap::MultiInputMapping;
|
||||
const float AXIS_BIND_THRESHOLD = 0.75f;
|
||||
const float AXIS_BIND_THRESHOLD_MOUSE = 0.01f;
|
||||
|
||||
ControlMapper g_controlMapper;
|
||||
|
||||
// We reduce the threshold of some axes when another axis on the same stick is active.
|
||||
// This makes it easier to hit diagonals if you bind an analog stick to four face buttons or D-Pad.
|
||||
@@ -146,19 +147,6 @@ void ConvertAnalogStick(float x, float y, float *outX, float *outY) {
|
||||
*outY = Clamp(y / norm * mappedNorm, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ControlMapper::SetCallbacks(
|
||||
std::function<void(VirtKey, bool)> onVKey,
|
||||
std::function<void(VirtKey, float)> onVKeyAnalog,
|
||||
std::function<void(uint32_t, uint32_t)> updatePSPButtons,
|
||||
std::function<void(int, int, float, float)> setPSPAnalog,
|
||||
std::function<void(int, float, float)> setRawAnalog) {
|
||||
onVKey_ = onVKey;
|
||||
onVKeyAnalog_ = onVKeyAnalog;
|
||||
updatePSPButtons_ = updatePSPButtons;
|
||||
setPSPAnalog_ = setPSPAnalog;
|
||||
setRawAnalog_ = setRawAnalog;
|
||||
}
|
||||
|
||||
void ControlMapper::SetPSPAxis(int device, int stick, char axis, float value) {
|
||||
const int axisId = axis == 'X' ? 0 : 1;
|
||||
if (stick != 0 && stick != 1) {
|
||||
@@ -171,11 +159,11 @@ void ControlMapper::SetPSPAxis(int device, int stick, char axis, float value) {
|
||||
|
||||
position[axisId] = value;
|
||||
|
||||
float x = position[0];
|
||||
float y = position[1];
|
||||
const float x = position[0];
|
||||
const float y = position[1];
|
||||
|
||||
if (setRawAnalog_) {
|
||||
setRawAnalog_(stick, x, y);
|
||||
for (auto listener : listeners_) {
|
||||
listener->SetRawAnalog(stick, x, y);
|
||||
}
|
||||
|
||||
// NOTE: We need to use single-axis checks, since the other axis might be from another device,
|
||||
@@ -208,7 +196,9 @@ void ControlMapper::UpdateAnalogOutput(int stick) {
|
||||
}
|
||||
converted_[stick][0] = x;
|
||||
converted_[stick][1] = y;
|
||||
setPSPAnalog_(iInternalScreenRotationCached_, stick, x, y);
|
||||
for (auto listener : listeners_) {
|
||||
listener->SetPSPAnalog(iInternalScreenRotationCached_, stick, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlMapper::ForceReleaseVKey(int vkey) {
|
||||
@@ -416,7 +406,9 @@ bool ControlMapper::UpdatePSPState(const InputMapping &changedMapping, double no
|
||||
}
|
||||
|
||||
// We only request changing the buttons where the mapped input was involved.
|
||||
updatePSPButtons_(buttonMask & changedButtonMask, (~buttonMask) & changedButtonMask);
|
||||
for (auto listener : listeners_) {
|
||||
listener->UpdatePSPButtons(buttonMask & changedButtonMask, (~buttonMask) & changedButtonMask);
|
||||
}
|
||||
|
||||
bool keyInputUsed = changedButtonMask != 0;
|
||||
bool updateAnalogSticks = false;
|
||||
@@ -579,16 +571,22 @@ void ControlMapper::ToggleSwapAxes() {
|
||||
|
||||
swapAxes_ = !swapAxes_;
|
||||
|
||||
updatePSPButtons_(0, CTRL_LEFT | CTRL_RIGHT | CTRL_UP | CTRL_DOWN);
|
||||
for (auto listener : listeners_) {
|
||||
listener->UpdatePSPButtons(0, CTRL_LEFT | CTRL_RIGHT | CTRL_UP | CTRL_DOWN);
|
||||
}
|
||||
|
||||
for (VirtKey vkey = VIRTKEY_FIRST; vkey < VIRTKEY_LAST; vkey = (VirtKey)(vkey + 1)) {
|
||||
if (IsSwappableVKey(vkey)) {
|
||||
if (virtKeyOn_[vkey - VIRTKEY_FIRST]) {
|
||||
onVKey_(vkey, false);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnVKey(vkey, false);
|
||||
}
|
||||
virtKeyOn_[vkey - VIRTKEY_FIRST] = false;
|
||||
}
|
||||
if (virtKeys_[vkey - VIRTKEY_FIRST] > 0.0f) {
|
||||
onVKeyAnalog_(vkey, 0.0f);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnVKeyAnalog(vkey, 0.0f);
|
||||
}
|
||||
virtKeys_[vkey - VIRTKEY_FIRST] = 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -657,12 +655,16 @@ void ControlMapper::Update(const DisplayLayoutConfig &config, double now) {
|
||||
float x = std::min(1.0f, std::max(-1.0f, 1.42f * (float)cos(now * -g_Config.fAnalogAutoRotSpeed)));
|
||||
float y = std::min(1.0f, std::max(-1.0f, 1.42f * (float)sin(now * -g_Config.fAnalogAutoRotSpeed)));
|
||||
|
||||
setPSPAnalog_(iInternalScreenRotationCached_, 0, x, y);
|
||||
for (auto listener : listeners_) {
|
||||
listener->SetPSPAnalog(iInternalScreenRotationCached_, 0, x, y);
|
||||
}
|
||||
} else if (autoRotatingAnalogCCW_) {
|
||||
float x = std::min(1.0f, std::max(-1.0f, 1.42f * (float)cos(now * g_Config.fAnalogAutoRotSpeed)));
|
||||
float y = std::min(1.0f, std::max(-1.0f, 1.42f * (float)sin(now * g_Config.fAnalogAutoRotSpeed)));
|
||||
|
||||
setPSPAnalog_(iInternalScreenRotationCached_, 0, x, y);
|
||||
for (auto listener : listeners_) {
|
||||
listener->SetPSPAnalog(iInternalScreenRotationCached_, 0, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,9 +685,13 @@ void ControlMapper::PSPKey(int deviceId, int pspKeyCode, KeyInputFlags flags) {
|
||||
} else {
|
||||
// INFO_LOG(Log::System, "pspKey %d %d", pspKeyCode, flags);
|
||||
if (flags & KeyInputFlags::DOWN)
|
||||
updatePSPButtons_(pspKeyCode, 0);
|
||||
for (auto listener : listeners_) {
|
||||
listener->UpdatePSPButtons(pspKeyCode, 0);
|
||||
}
|
||||
if (flags & KeyInputFlags::UP)
|
||||
updatePSPButtons_(0, pspKeyCode);
|
||||
for (auto listener : listeners_) {
|
||||
listener->UpdatePSPButtons(0, pspKeyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,8 +712,9 @@ void ControlMapper::onVKeyAnalog(int deviceId, VirtKey vkey, float value) {
|
||||
case VIRTKEY_AXIS_RIGHT_Y_MIN: stick = CTRL_STICK_RIGHT; axis = 'Y'; sign = -1.0f; break;
|
||||
case VIRTKEY_AXIS_RIGHT_Y_MAX: stick = CTRL_STICK_RIGHT; axis = 'Y'; break;
|
||||
default:
|
||||
if (onVKeyAnalog_)
|
||||
onVKeyAnalog_(vkey, value);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnVKeyAnalog(vkey, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (oppositeVKey != 0) {
|
||||
@@ -728,7 +735,9 @@ void ControlMapper::onVKey(VirtKey vkey, bool down) {
|
||||
autoRotatingAnalogCCW_ = false;
|
||||
} else {
|
||||
autoRotatingAnalogCW_ = false;
|
||||
setPSPAnalog_(iInternalScreenRotationCached_, 0, 0.0f, 0.0f);
|
||||
for (auto listener : listeners_) {
|
||||
listener->SetPSPAnalog(iInternalScreenRotationCached_, 0, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VIRTKEY_ANALOG_ROTATE_CCW:
|
||||
@@ -737,12 +746,15 @@ void ControlMapper::onVKey(VirtKey vkey, bool down) {
|
||||
autoRotatingAnalogCCW_ = true;
|
||||
} else {
|
||||
autoRotatingAnalogCCW_ = false;
|
||||
setPSPAnalog_(iInternalScreenRotationCached_, 0, 0.0f, 0.0f);
|
||||
for (auto listener : listeners_) {
|
||||
listener->SetPSPAnalog(iInternalScreenRotationCached_, 0, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (onVKey_)
|
||||
onVKey_(vkey, down);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnVKey(vkey, down);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -763,3 +775,11 @@ void ControlMapper::GetDebugString(char *buffer, size_t bufSize) const {
|
||||
str << "Lstick: " << converted_[0][0] << ", " << converted_[0][1] << std::endl;
|
||||
truncate_cpy(buffer, bufSize, str.str().c_str());
|
||||
}
|
||||
|
||||
void ControlMapper::RemoveListener(ControlListener *listener) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
auto it = std::find(listeners_.begin(), listeners_.end(), listener);
|
||||
if (it != listeners_.end()) {
|
||||
listeners_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-11
@@ -6,8 +6,21 @@
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
struct DisplayLayoutConfig;
|
||||
|
||||
// Pure interface.
|
||||
class ControlListener {
|
||||
public:
|
||||
virtual ~ControlListener() = default;
|
||||
virtual void OnVKey(VirtKey vkey, bool down) {}
|
||||
virtual void OnVKeyAnalog(VirtKey vkey, float value) {}
|
||||
virtual void UpdatePSPButtons(uint32_t buttonMask, uint32_t changedMask) {}
|
||||
virtual void SetPSPAnalog(int rotation, int stick, float x, float y) {}
|
||||
virtual void SetRawAnalog(int stick, float x, float y) {}
|
||||
};
|
||||
|
||||
// Utilities for mapping input events to PSP inputs and virtual keys.
|
||||
// Main use is of course from EmuScreen.cpp, but also useful from control settings etc.
|
||||
class ControlMapper {
|
||||
@@ -21,12 +34,10 @@ public:
|
||||
|
||||
// Required callbacks.
|
||||
// TODO: These are so many now that a virtual interface might be more appropriate..
|
||||
void SetCallbacks(
|
||||
std::function<void(VirtKey, bool)> onVKey,
|
||||
std::function<void(VirtKey, float)> onVKeyAnalog,
|
||||
std::function<void(uint32_t, uint32_t)> updatePSPButtons,
|
||||
std::function<void(int, int, float, float)> setPSPAnalog,
|
||||
std::function<void(int, float, float)> setRawAnalog);
|
||||
void AddListener(ControlListener *listener) {
|
||||
listeners_.push_back(listener);
|
||||
}
|
||||
void RemoveListener(ControlListener *listener);
|
||||
|
||||
// Inject raw PSP key input directly, such as from touch screen controls.
|
||||
// Combined with the mapped input. Unlike __Ctrl APIs, this supports
|
||||
@@ -96,12 +107,10 @@ private:
|
||||
std::map<InputMapping, InputSample> curInput_;
|
||||
|
||||
// Callbacks
|
||||
std::function<void(VirtKey, bool)> onVKey_;
|
||||
std::function<void(VirtKey, float)> onVKeyAnalog_;
|
||||
std::function<void(uint32_t, uint32_t)> updatePSPButtons_;
|
||||
std::function<void(int, int, float, float)> setPSPAnalog_;
|
||||
std::function<void(int, float, float)> setRawAnalog_;
|
||||
std::vector<ControlListener *> listeners_;
|
||||
};
|
||||
|
||||
void ConvertAnalogStick(float x, float y, float *outX, float *outY);
|
||||
float GetDeviceAxisThreshold(int device, const InputMapping &mapping);
|
||||
|
||||
extern ControlMapper g_controlMapper;
|
||||
|
||||
+18
-15
@@ -480,22 +480,25 @@ void KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) {
|
||||
}
|
||||
|
||||
AnalogCalibrationScreen::AnalogCalibrationScreen(const Path &gamePath) : UITwoPaneBaseDialogScreen(gamePath, TwoPaneFlags::SettingsCanScroll) {
|
||||
mapper_.SetCallbacks(
|
||||
[](int vkey, bool down) {},
|
||||
[](int vkey, float analogValue) {},
|
||||
[&](uint32_t bitsToSet, uint32_t bitsToClear) {},
|
||||
[&](int iInternalRotation, int stick, float x, float y) {
|
||||
analogX_[stick] = x;
|
||||
analogY_[stick] = y;
|
||||
},
|
||||
[&](int stick, float x, float y) {
|
||||
rawX_[stick] = x;
|
||||
rawY_[stick] = y;
|
||||
});
|
||||
g_controlMapper.AddListener(this);
|
||||
}
|
||||
|
||||
AnalogCalibrationScreen::~AnalogCalibrationScreen() {
|
||||
g_controlMapper.RemoveListener(this);
|
||||
}
|
||||
|
||||
void AnalogCalibrationScreen::SetPSPAnalog(int rotation, int stick, float x, float y) {
|
||||
analogX_[stick] = x;
|
||||
analogY_[stick] = y;
|
||||
}
|
||||
|
||||
void AnalogCalibrationScreen::SetRawAnalog(int stick, float x, float y) {
|
||||
rawX_[stick] = x;
|
||||
rawY_[stick] = y;
|
||||
}
|
||||
|
||||
void AnalogCalibrationScreen::update() {
|
||||
mapper_.Update(g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()), time_now_d());
|
||||
g_controlMapper.Update(g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()), time_now_d());
|
||||
// We ignore the secondary stick for now and just use the two views
|
||||
// for raw and psp input.
|
||||
if (stickView_[0]) {
|
||||
@@ -512,7 +515,7 @@ bool AnalogCalibrationScreen::key(const KeyInput &key) {
|
||||
|
||||
// Allow testing auto-rotation. If it collides with UI keys, too bad.
|
||||
bool pauseTrigger = false;
|
||||
mapper_.Key(key, &pauseTrigger);
|
||||
g_controlMapper.Key(key, &pauseTrigger);
|
||||
|
||||
if (UI::IsEscapeKey(key)) {
|
||||
TriggerFinish(DR_BACK);
|
||||
@@ -526,7 +529,7 @@ void AnalogCalibrationScreen::axis(const AxisInput &axis) {
|
||||
// UIScreen::axis(axis);
|
||||
|
||||
// Instead we just send the input directly to the mapper, that we'll visualize.
|
||||
mapper_.Axis(&axis, 1);
|
||||
g_controlMapper.Axis(&axis, 1);
|
||||
}
|
||||
|
||||
std::string_view AnalogCalibrationScreen::GetTitle() const {
|
||||
|
||||
@@ -125,9 +125,10 @@ private:
|
||||
|
||||
class JoystickHistoryView;
|
||||
|
||||
class AnalogCalibrationScreen : public UITwoPaneBaseDialogScreen {
|
||||
class AnalogCalibrationScreen : public UITwoPaneBaseDialogScreen, protected ControlListener {
|
||||
public:
|
||||
AnalogCalibrationScreen(const Path &gamePath);
|
||||
~AnalogCalibrationScreen();
|
||||
|
||||
bool key(const KeyInput &key) override;
|
||||
void axis(const AxisInput &axis) override;
|
||||
@@ -140,12 +141,13 @@ protected:
|
||||
void CreateSettingsViews(UI::ViewGroup *parent) override;
|
||||
void CreateContentViews(UI::ViewGroup *parent) override;
|
||||
|
||||
void SetPSPAnalog(int rotation, int stick, float x, float y) override;
|
||||
void SetRawAnalog(int stick, float x, float y) override;
|
||||
|
||||
std::string_view GetTitle() const override;
|
||||
private:
|
||||
void OnResetToDefaults(UI::EventParams &e);
|
||||
|
||||
ControlMapper mapper_;
|
||||
|
||||
float analogX_[2]{};
|
||||
float analogY_[2]{};
|
||||
float rawX_[2]{};
|
||||
|
||||
+68
-60
@@ -126,7 +126,20 @@ static void AssertCancelCallback(const char *message, void *userdata) {
|
||||
}
|
||||
|
||||
// Handles control rotation due to internal screen rotation.
|
||||
static void SetPSPAnalog(int iInternalScreenRotation, int stick, float x, float y) {
|
||||
void EmuScreen::UpdatePSPButtons(uint32_t bitsToSet, uint32_t bitsToClear) {
|
||||
if (!isOnTop_) {
|
||||
// Auto-release inputs
|
||||
bitsToSet = 0;
|
||||
}
|
||||
__CtrlUpdateButtons(bitsToSet, bitsToClear);
|
||||
}
|
||||
|
||||
void EmuScreen::SetPSPAnalog(int iInternalScreenRotation, int stick, float x, float y) {
|
||||
if (!isOnTop_) {
|
||||
x = 0.0f;
|
||||
y = 0.0f;
|
||||
}
|
||||
|
||||
switch (iInternalScreenRotation) {
|
||||
case ROTATION_LOCKED_HORIZONTAL:
|
||||
// Standard rotation. No change.
|
||||
@@ -158,14 +171,7 @@ static void SetPSPAnalog(int iInternalScreenRotation, int stick, float x, float
|
||||
EmuScreen::EmuScreen(const Path &filename)
|
||||
: gamePath_(filename) {
|
||||
saveStateSlot_ = SaveState::GetCurrentSlot();
|
||||
controlMapper_.SetCallbacks(
|
||||
std::bind(&EmuScreen::onVKey, this, _1, _2),
|
||||
std::bind(&EmuScreen::onVKeyAnalog, this, _1, _2),
|
||||
[](uint32_t bitsToSet, uint32_t bitsToClear) {
|
||||
__CtrlUpdateButtons(bitsToSet, bitsToClear);
|
||||
},
|
||||
&SetPSPAnalog,
|
||||
nullptr);
|
||||
g_controlMapper.AddListener(this);
|
||||
|
||||
_dbg_assert_(coreState == CORE_POWERDOWN);
|
||||
|
||||
@@ -449,6 +455,8 @@ void EmuScreen::bootComplete() {
|
||||
}
|
||||
|
||||
EmuScreen::~EmuScreen() {
|
||||
g_controlMapper.RemoveListener(this);
|
||||
|
||||
if (imguiInited_) {
|
||||
ImGui_ImplThin3d_Shutdown();
|
||||
ImGui::DestroyContext(ctx_);
|
||||
@@ -540,10 +548,11 @@ void EmuScreen::focusChanged(ScreenFocusChange focusChange) {
|
||||
switch (focusChange) {
|
||||
case ScreenFocusChange::FOCUS_LOST_TOP:
|
||||
g_Config.TimeTracker().Stop(gameID);
|
||||
controlMapper_.ReleaseAll();
|
||||
isOnTop_ = false;
|
||||
break;
|
||||
case ScreenFocusChange::FOCUS_BECAME_TOP:
|
||||
g_Config.TimeTracker().Start(gameID);
|
||||
isOnTop_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -739,38 +748,14 @@ static void ShowFpsLimitNotice() {
|
||||
g_OSD.SetFlags("altspeed", OSDMessageFlags::Transparent);
|
||||
}
|
||||
|
||||
void EmuScreen::onVKey(VirtKey virtualKeyCode, bool down) {
|
||||
void EmuScreen::OnVKey(VirtKey virtualKeyCode, bool down) {
|
||||
if (!isOnTop_)
|
||||
return;
|
||||
|
||||
auto sc = GetI18NCategory(I18NCat::SCREEN);
|
||||
auto mc = GetI18NCategory(I18NCat::MAPPABLECONTROLS);
|
||||
|
||||
switch (virtualKeyCode) {
|
||||
case VIRTKEY_TOGGLE_DEBUGGER:
|
||||
if (down) {
|
||||
g_Config.bShowImDebugger = !g_Config.bShowImDebugger;
|
||||
}
|
||||
break;
|
||||
case VIRTKEY_TOGGLE_TILT:
|
||||
if (down) {
|
||||
g_Config.bTiltInputEnabled = !g_Config.bTiltInputEnabled;
|
||||
if (!g_Config.bTiltInputEnabled) {
|
||||
// Reset whatever got tilted.
|
||||
switch (g_Config.iTiltInputType) {
|
||||
case TILT_ANALOG:
|
||||
__CtrlSetAnalogXY(0, 0, 0);
|
||||
break;
|
||||
case TILT_ACTION_BUTTON:
|
||||
__CtrlUpdateButtons(0, CTRL_CROSS | CTRL_CIRCLE | CTRL_SQUARE | CTRL_TRIANGLE);
|
||||
break;
|
||||
case TILT_DPAD:
|
||||
__CtrlUpdateButtons(0, CTRL_UP | CTRL_DOWN | CTRL_LEFT | CTRL_RIGHT);
|
||||
break;
|
||||
case TILT_TRIGGER_BUTTONS:
|
||||
__CtrlUpdateButtons(0, CTRL_LTRIGGER | CTRL_RTRIGGER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VIRTKEY_FASTFORWARD:
|
||||
if (down && !NetworkWarnUserIfOnlineAndCantSpeed() && !bootPending_) {
|
||||
/*
|
||||
@@ -827,15 +812,6 @@ void EmuScreen::onVKey(VirtKey virtualKeyCode, bool down) {
|
||||
}
|
||||
break;
|
||||
|
||||
case VIRTKEY_PAUSE:
|
||||
if (down) {
|
||||
// Note: We don't check NetworkWarnUserIfOnlineAndCantSpeed, because we can keep
|
||||
// running in the background of the menu.
|
||||
pauseTrigger_ = true;
|
||||
controlMapper_.ForceReleaseVKey(virtualKeyCode);
|
||||
}
|
||||
break;
|
||||
|
||||
case VIRTKEY_RESET_EMULATION:
|
||||
if (down) {
|
||||
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
|
||||
@@ -914,16 +890,45 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) {
|
||||
auto sc = GetI18NCategory(I18NCat::SCREEN);
|
||||
|
||||
switch (virtKey) {
|
||||
case VIRTKEY_PAUSE:
|
||||
// Note: We don't check NetworkWarnUserIfOnlineAndCantSpeed, because we can keep
|
||||
// running in the background of the menu.
|
||||
pauseTrigger_ = true;
|
||||
break;
|
||||
|
||||
case VIRTKEY_TOGGLE_DEBUGGER:
|
||||
g_Config.bShowImDebugger = !g_Config.bShowImDebugger;
|
||||
break;
|
||||
case VIRTKEY_TOGGLE_TILT:
|
||||
g_Config.bTiltInputEnabled = !g_Config.bTiltInputEnabled;
|
||||
if (!g_Config.bTiltInputEnabled) {
|
||||
// Reset whatever got tilted.
|
||||
switch (g_Config.iTiltInputType) {
|
||||
case TILT_ANALOG:
|
||||
__CtrlSetAnalogXY(0, 0, 0);
|
||||
break;
|
||||
case TILT_ACTION_BUTTON:
|
||||
__CtrlUpdateButtons(0, CTRL_CROSS | CTRL_CIRCLE | CTRL_SQUARE | CTRL_TRIANGLE);
|
||||
break;
|
||||
case TILT_DPAD:
|
||||
__CtrlUpdateButtons(0, CTRL_UP | CTRL_DOWN | CTRL_LEFT | CTRL_RIGHT);
|
||||
break;
|
||||
case TILT_TRIGGER_BUTTONS:
|
||||
__CtrlUpdateButtons(0, CTRL_LTRIGGER | CTRL_RTRIGGER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VIRTKEY_OPENCHAT:
|
||||
if (g_Config.bEnableNetworkChat && !g_Config.bShowImDebugger) {
|
||||
UI::EventParams e{};
|
||||
OnChatMenu.Trigger(e);
|
||||
controlMapper_.ForceReleaseVKey(VIRTKEY_OPENCHAT);
|
||||
g_controlMapper.ForceReleaseVKey(VIRTKEY_OPENCHAT);
|
||||
}
|
||||
break;
|
||||
|
||||
case VIRTKEY_AXIS_SWAP:
|
||||
controlMapper_.ToggleSwapAxes();
|
||||
g_controlMapper.ToggleSwapAxes();
|
||||
g_OSD.Show(OSDType::MESSAGE_INFO, mc->T("AxisSwap")); // best string we have.
|
||||
break;
|
||||
|
||||
@@ -1081,7 +1086,10 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmuScreen::onVKeyAnalog(VirtKey virtualKeyCode, float value) {
|
||||
void EmuScreen::OnVKeyAnalog(VirtKey virtualKeyCode, float value) {
|
||||
if (!isOnTop_)
|
||||
return;
|
||||
|
||||
if (virtualKeyCode != VIRTKEY_SPEED_ANALOG) {
|
||||
return;
|
||||
}
|
||||
@@ -1143,7 +1151,7 @@ bool EmuScreen::UnsyncKey(const KeyInput &key) {
|
||||
if (mappingFound) {
|
||||
for (auto b : pspButtons) {
|
||||
if (b == VIRTKEY_TOGGLE_DEBUGGER || b == VIRTKEY_PAUSE) {
|
||||
return controlMapper_.Key(key, &pauseTrigger_);
|
||||
return g_controlMapper.Key(key, &pauseTrigger_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1153,28 +1161,28 @@ bool EmuScreen::UnsyncKey(const KeyInput &key) {
|
||||
switch (key.deviceId) {
|
||||
case DEVICE_ID_KEYBOARD:
|
||||
if (!ImGui::GetIO().WantCaptureKeyboard) {
|
||||
controlMapper_.Key(key, &pauseTrigger_);
|
||||
g_controlMapper.Key(key, &pauseTrigger_);
|
||||
}
|
||||
break;
|
||||
case DEVICE_ID_MOUSE:
|
||||
if (!ImGui::GetIO().WantCaptureMouse) {
|
||||
controlMapper_.Key(key, &pauseTrigger_);
|
||||
g_controlMapper.Key(key, &pauseTrigger_);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
controlMapper_.Key(key, &pauseTrigger_);
|
||||
g_controlMapper.Key(key, &pauseTrigger_);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Let up-events through to the controlMapper_ so input doesn't get stuck.
|
||||
if (key.flags & KeyInputFlags::UP) {
|
||||
controlMapper_.Key(key, &pauseTrigger_);
|
||||
g_controlMapper.Key(key, &pauseTrigger_);
|
||||
}
|
||||
}
|
||||
|
||||
return UIScreen::UnsyncKey(key);
|
||||
}
|
||||
return controlMapper_.Key(key, &pauseTrigger_);
|
||||
return g_controlMapper.Key(key, &pauseTrigger_);
|
||||
}
|
||||
|
||||
void EmuScreen::UnsyncAxis(const AxisInput *axes, size_t count) {
|
||||
@@ -1184,7 +1192,7 @@ void EmuScreen::UnsyncAxis(const AxisInput *axes, size_t count) {
|
||||
return UIScreen::UnsyncAxis(axes, count);
|
||||
}
|
||||
|
||||
return controlMapper_.Axis(axes, count);
|
||||
return g_controlMapper.Axis(axes, count);
|
||||
}
|
||||
|
||||
bool EmuScreen::key(const KeyInput &key) {
|
||||
@@ -1262,7 +1270,7 @@ void EmuScreen::CreateViews() {
|
||||
const Bounds &bounds = screenManager()->getUIContext()->GetLayoutBounds();
|
||||
InitPadLayout(&touch, deviceOrientation, bounds.w, bounds.h);
|
||||
|
||||
root_ = CreatePadLayout(touch, bounds.w, bounds.h, &pauseTrigger_, &controlMapper_);
|
||||
root_ = CreatePadLayout(touch, bounds.w, bounds.h, &pauseTrigger_, &g_controlMapper);
|
||||
if (g_Config.bShowDeveloperMenu) {
|
||||
root_->Add(new Button(dev->T("DevMenu")))->OnClick.Handle(this, &EmuScreen::OnDevTools);
|
||||
}
|
||||
@@ -1475,7 +1483,7 @@ void EmuScreen::update() {
|
||||
double now = time_now_d();
|
||||
|
||||
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
|
||||
controlMapper_.Update(config, now);
|
||||
g_controlMapper.Update(config, now);
|
||||
|
||||
if (saveStatePreview_ && !bootPending_) {
|
||||
int currentSlot = SaveState::GetCurrentSlot();
|
||||
@@ -1944,7 +1952,7 @@ void EmuScreen::renderUI() {
|
||||
|
||||
if (PSP_IsInited()) {
|
||||
if ((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::CONTROL) {
|
||||
DrawControlMapperOverlay(ctx, ctx->GetLayoutBounds(), controlMapper_);
|
||||
DrawControlMapperOverlay(ctx, ctx->GetLayoutBounds(), g_controlMapper);
|
||||
}
|
||||
if (g_Config.iShowStatusFlags) {
|
||||
DrawFPS(ctx, ctx->GetLayoutBounds());
|
||||
|
||||
+10
-5
@@ -36,7 +36,7 @@ struct AxisInput;
|
||||
class AsyncImageFileView;
|
||||
class ChatMenu;
|
||||
|
||||
class EmuScreen : public UIScreen {
|
||||
class EmuScreen : public UIScreen, public ControlListener {
|
||||
public:
|
||||
EmuScreen(const Path &filename);
|
||||
~EmuScreen();
|
||||
@@ -72,6 +72,13 @@ protected:
|
||||
void focusChanged(ScreenFocusChange focusChange) override;
|
||||
ScreenRenderFlags PreRender(ScreenRenderMode mode) override;
|
||||
|
||||
// ControlListener implementations
|
||||
void OnVKey(VirtKey virtualKeyCode, bool down);
|
||||
void OnVKeyAnalog(VirtKey virtualKeyCode, float value);
|
||||
void UpdatePSPButtons(uint32_t buttonMask, uint32_t changedMask) override;
|
||||
void SetPSPAnalog(int rotation, int stick, float x, float y);
|
||||
void SetRawAnalog(int deviceId, float x, float y) {}
|
||||
|
||||
private:
|
||||
void CreateViews() override;
|
||||
ScreenRenderFlags RunEmulation(bool skipBufferEffects);
|
||||
@@ -87,8 +94,6 @@ private:
|
||||
void runImDebugger();
|
||||
void renderImDebugger();
|
||||
|
||||
void onVKey(VirtKey virtualKeyCode, bool down);
|
||||
void onVKeyAnalog(VirtKey virtualKeyCode, float value);
|
||||
|
||||
void AutoLoadSaveState();
|
||||
bool checkPowerDown();
|
||||
@@ -136,8 +141,6 @@ private:
|
||||
|
||||
std::string extraAssertInfoStr_;
|
||||
|
||||
ControlMapper controlMapper_;
|
||||
|
||||
std::unique_ptr<ImDebugger> imDebugger_ = nullptr;
|
||||
ImCommand imCmd_{}; // needed to buffer commands in case imgui wasn't created yet.
|
||||
|
||||
@@ -163,6 +166,8 @@ private:
|
||||
bool autoLoadFailed_ = false; // to prevent repeat reloads
|
||||
bool readyToFinishBoot_ = false;
|
||||
bool skipBufferEffects_ = false; // cached state, fetched once per frame.
|
||||
|
||||
bool isOnTop_ = true;
|
||||
};
|
||||
|
||||
bool MustRunBehind();
|
||||
|
||||
+1
-1
@@ -1432,7 +1432,7 @@ void MainScreen::CreateViews() {
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
ImageID icon(g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN");
|
||||
fullscreenButton_ = logo->Add(new Button(gr->T("FullScreen", "Full Screen"), icon, new AnchorLayoutParams(48, 48, NONE, 0, 0, NONE, Centering::None)));
|
||||
fullscreenButton_ = logo->Add(new Button("", icon, new AnchorLayoutParams(48, 48, NONE, 0, 0, NONE, Centering::None)));
|
||||
fullscreenButton_->SetIgnoreText(true);
|
||||
fullscreenButton_->OnClick.Add([this](UI::EventParams &e) {
|
||||
if (fullscreenButton_) {
|
||||
|
||||
+18
-16
@@ -352,30 +352,32 @@ GamePauseScreen::GamePauseScreen(const Path &filename, bool bootPending)
|
||||
SetExtraAssertInfo(assertStr.c_str());
|
||||
saveStatePrefix_ = SaveState::GetGamePrefix(g_paramSFO);
|
||||
SaveState::Rescan(saveStatePrefix_);
|
||||
g_controlMapper.AddListener(this);
|
||||
createdTime_ = time_now_d();
|
||||
}
|
||||
|
||||
GamePauseScreen::~GamePauseScreen() {
|
||||
g_controlMapper.RemoveListener(this);
|
||||
__DisplaySetWasPaused();
|
||||
}
|
||||
|
||||
bool GamePauseScreen::key(const KeyInput &key) {
|
||||
bool handled = UIDialogScreen::key(key);
|
||||
bool GamePauseScreen::UnsyncKey(const KeyInput &key) {
|
||||
int retval = UIScreen::UnsyncKey(key);
|
||||
bool pauseTrigger = false;
|
||||
return retval || g_controlMapper.Key(key, &pauseTrigger);
|
||||
}
|
||||
|
||||
if (!handled && (key.flags & KeyInputFlags::DOWN)) {
|
||||
// Special case to be able to unpause with a bound pause key.
|
||||
// Normally we can't bind keys used in the UI.
|
||||
InputMapping mapping(key.deviceId, key.keyCode);
|
||||
std::vector<int> pspButtons;
|
||||
KeyMap::InputMappingToPspButton(mapping, &pspButtons);
|
||||
for (auto button : pspButtons) {
|
||||
if (button == VIRTKEY_PAUSE) {
|
||||
TriggerFinish(DR_CANCEL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
void GamePauseScreen::UnsyncAxis(const AxisInput *axes, size_t count) {
|
||||
UIScreen::UnsyncAxis(axes, count);
|
||||
g_controlMapper.Axis(axes, count);
|
||||
}
|
||||
|
||||
void GamePauseScreen::OnVKey(VirtKey virtualKeyCode, bool down) {
|
||||
// Simple de-bounce using createdTime_, just to be safe.
|
||||
if (down && virtualKeyCode == VIRTKEY_PAUSE && time_now_d() > createdTime_ + 0.1) {
|
||||
finishNextFrame_ = true;
|
||||
finishNextFrameResult_ = DR_BACK;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems) {
|
||||
|
||||
+9
-2
@@ -23,17 +23,17 @@
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Core/ControlMapper.h"
|
||||
#include "UI/BaseScreens.h"
|
||||
#include "UI/Screen.h"
|
||||
#include "UI/GameInfoCache.h"
|
||||
|
||||
class GamePauseScreen : public UIBaseDialogScreen {
|
||||
class GamePauseScreen : public UIBaseDialogScreen, protected ControlListener {
|
||||
public:
|
||||
GamePauseScreen(const Path &filename, bool bootPending);
|
||||
~GamePauseScreen();
|
||||
|
||||
void dialogFinished(const Screen *dialog, DialogResult dr) override;
|
||||
bool key(const KeyInput &key) override;
|
||||
|
||||
const char *tag() const override { return "GamePause"; }
|
||||
|
||||
@@ -42,6 +42,12 @@ protected:
|
||||
void update() override;
|
||||
UI::Margins RootMargins() const override;
|
||||
|
||||
// For processing of certain mapped keys.
|
||||
bool UnsyncKey(const KeyInput &key) override;
|
||||
void UnsyncAxis(const AxisInput *axes, size_t count) override;
|
||||
|
||||
void OnVKey(VirtKey virtualKeyCode, bool down);
|
||||
|
||||
private:
|
||||
void CreateSavestateControls(UI::LinearLayout *viewGroup);
|
||||
|
||||
@@ -77,6 +83,7 @@ private:
|
||||
bool bootPending_ = false;
|
||||
|
||||
std::string saveStatePrefix_;
|
||||
double createdTime_ = 0.0;
|
||||
};
|
||||
|
||||
std::string GetConfirmExitMessage();
|
||||
|
||||
Reference in New Issue
Block a user