mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
GamepadEmu: bounds-check touch pointer IDs before use
TouchInput::id was used directly to index the global primaryButton[] array (MultiTouchButton::Touch) and to shift pointer bitmasks (PSPDpad/PSPStick/PSPCustomStick/GestureGamepad::Touch), guarded only by a debug-only assert in one of the five call sites - a no-op in release builds. input.id isn't always a small sequential slot in [0, TOUCH_MAX_POINTERS): SDL assigns SDL_FingerID values directly, Android pointer IDs can go up to 31, and UWP's TouchMapper allocates one more slot (11) than TOUCH_MAX_POINTERS (10) and can also return -1 when it runs out of slots - all reachable through ordinary multi-touch use, no malicious input required. Also apply bounds check to the PER_GAME gesture config ints (iDoubleTapGesture/iSwipeUp/Down/Left/Right) before indexing GestureKey::keyList[] with them. Additionally, minor cleanup on Android and moves the TouchMapper helper out from UWP to InputState.h.
This commit is contained in:
1 parent
8f5e984238
commit
9315c0953a
6 files changed
+96
-50
No files matched your search
@@ -6,6 +6,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/Input/KeyCodes.h"
|
||||
@@ -225,3 +226,45 @@ int GetAnalogYDirection(InputDeviceID deviceId);
|
||||
|
||||
// Gross hack unfortunately.
|
||||
extern bool g_IsMappingMouseInput;
|
||||
|
||||
// General helper for backends that use different types of touch IDs.
|
||||
// Warning: If it can't map, IDs come out as -1.
|
||||
class TouchMapper {
|
||||
public:
|
||||
struct Touch {
|
||||
bool inUse = false;
|
||||
uint64_t uid = 0;
|
||||
};
|
||||
|
||||
int TouchId(uint64_t touch) {
|
||||
for (int touchIx = 0; touchIx < maxTouches; touchIx++)
|
||||
if (touches[touchIx].inUse && touches[touchIx].uid == touch)
|
||||
return touchIx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AddNewTouch(uint64_t touch) {
|
||||
for (int touchIx = 0; touchIx < maxTouches; touchIx++) {
|
||||
if (!touches[touchIx].inUse) {
|
||||
touches[touchIx].inUse = true;
|
||||
touches[touchIx].uid = touch;
|
||||
return touchIx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RemoveTouch(unsigned touch) {
|
||||
for (int touchIx = 0; touchIx < maxTouches; touchIx++) {
|
||||
if (touches[touchIx].inUse && touches[touchIx].uid == touch) {
|
||||
touches[touchIx].inUse = false;
|
||||
return touchIx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { maxTouches = 10 };
|
||||
Touch touches[maxTouches]{};
|
||||
};
|
||||
@@ -133,7 +133,7 @@ bool CreateSysDirectories() {
|
||||
INFO_LOG(Log::IO, "Creating '%s' and subdirs:", pspDir.c_str());
|
||||
File::CreateFullPath(pspDir);
|
||||
if (!File::Exists(pspDir)) {
|
||||
INFO_LOG(Log::IO, "Not a workable memstick directory. Giving up");
|
||||
INFO_LOG(Log::IO, "Not a workable memstick directory (%s). Giving up for now", pspDir.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+42
-7
@@ -131,7 +131,12 @@ bool MultiTouchButton::CanGlide() const {
|
||||
}
|
||||
|
||||
bool MultiTouchButton::Touch(const TouchInput &input) {
|
||||
_dbg_assert_(input.id >= 0 && input.id < TOUCH_MAX_POINTERS);
|
||||
// input.id comes from platform-specific touch/pointer IDs. Most of our
|
||||
// platforms try to remap to [0, TOUCH_MAX_POINTERS), and all will be updated
|
||||
// to do that in the future.
|
||||
if (input.id < 0 || input.id >= TOUCH_MAX_POINTERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retval = GamepadComponent::Touch(input);
|
||||
if ((input.flags & TouchInputFlags::DOWN) && bounds_.Contains(input.x, input.y)) {
|
||||
@@ -347,6 +352,11 @@ void PSPDpad::GetContentDimensions(const UIContext &dc, float &w, float &h) cons
|
||||
}
|
||||
|
||||
bool PSPDpad::Touch(const TouchInput &input) {
|
||||
// See the comment in MultiTouchButton::Touch().
|
||||
if (input.id < 0 || input.id >= TOUCH_MAX_POINTERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retval = GamepadComponent::Touch(input);
|
||||
|
||||
if (input.flags & TouchInputFlags::DOWN) {
|
||||
@@ -540,6 +550,11 @@ void PSPStick::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
bool PSPStick::Touch(const TouchInput &input) {
|
||||
// See the comment in MultiTouchButton::Touch().
|
||||
if (input.id < 0 || input.id >= TOUCH_MAX_POINTERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retval = GamepadComponent::Touch(input);
|
||||
if (input.flags & TouchInputFlags::RELEASE_ALL) {
|
||||
dragPointerId_ = -1;
|
||||
@@ -652,6 +667,10 @@ void PSPCustomStick::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
bool PSPCustomStick::Touch(const TouchInput &input) {
|
||||
if (input.id < 0 || input.id >= TOUCH_MAX_POINTERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retval = GamepadComponent::Touch(input);
|
||||
if (input.flags & TouchInputFlags::RELEASE_ALL) {
|
||||
dragPointerId_ = -1;
|
||||
@@ -1140,7 +1159,23 @@ GestureGamepad::~GestureGamepad() {
|
||||
}
|
||||
}
|
||||
|
||||
// The gesture config ints (iDoubleTapGesture/iSwipeUp/Down/Left/Right) are
|
||||
// PER_GAME config values loaded from an ini with no range clamp applied, unlike
|
||||
// the UI (a PopupMultiChoice) that normally sets them - a hand-edited, corrupted,
|
||||
// or version-skewed config could contain an out-of-range value, which would
|
||||
// otherwise index GestureKey::keyList[] out of bounds below. Mirrors the bounds
|
||||
// check PSPCustomStick::ProcessTouch already does for its own config->buttons[]
|
||||
// lookup.
|
||||
static bool ValidGestureKeyConfig(int config) {
|
||||
return config > 0 && (size_t)config <= ARRAY_SIZE(GestureKey::keyList);
|
||||
}
|
||||
|
||||
bool GestureGamepad::Touch(const TouchInput &input) {
|
||||
// See the comment in MultiTouchButton::Touch().
|
||||
if (input.id < 0 || input.id >= TOUCH_MAX_POINTERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const GestureControlConfig &zone = GetZone();
|
||||
|
||||
if (usedPointerMask & (1 << input.id)) {
|
||||
@@ -1169,7 +1204,7 @@ bool GestureGamepad::Touch(const TouchInput &input) {
|
||||
|
||||
const float now = time_now_d();
|
||||
if (now - lastTapRelease_ < 0.3f && !haveDoubleTapped_) {
|
||||
if (zone.iDoubleTapGesture != 0 )
|
||||
if (ValidGestureKeyConfig(zone.iDoubleTapGesture))
|
||||
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[zone.iDoubleTapGesture - 1], KeyInputFlags::DOWN);
|
||||
haveDoubleTapped_ = true;
|
||||
}
|
||||
@@ -1211,7 +1246,7 @@ bool GestureGamepad::Touch(const TouchInput &input) {
|
||||
lastTapRelease_ = time_now_d();
|
||||
|
||||
if (haveDoubleTapped_) {
|
||||
if (zone.iDoubleTapGesture != 0)
|
||||
if (ValidGestureKeyConfig(zone.iDoubleTapGesture))
|
||||
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[zone.iDoubleTapGesture - 1], KeyInputFlags::UP);
|
||||
haveDoubleTapped_ = false;
|
||||
}
|
||||
@@ -1247,7 +1282,7 @@ void GestureGamepad::Update() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetZone().iSwipeRight != 0) {
|
||||
if (ValidGestureKeyConfig(GetZone().iSwipeRight)) {
|
||||
if (dx > th) {
|
||||
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeRight - 1], KeyInputFlags::DOWN);
|
||||
swipeRightReleased_ = false;
|
||||
@@ -1256,7 +1291,7 @@ void GestureGamepad::Update() {
|
||||
swipeRightReleased_ = true;
|
||||
}
|
||||
}
|
||||
if (GetZone().iSwipeLeft != 0) {
|
||||
if (ValidGestureKeyConfig(GetZone().iSwipeLeft)) {
|
||||
if (dx < -th) {
|
||||
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeLeft - 1], KeyInputFlags::DOWN);
|
||||
swipeLeftReleased_ = false;
|
||||
@@ -1265,7 +1300,7 @@ void GestureGamepad::Update() {
|
||||
swipeLeftReleased_ = true;
|
||||
}
|
||||
}
|
||||
if (GetZone().iSwipeUp != 0) {
|
||||
if (ValidGestureKeyConfig(GetZone().iSwipeUp)) {
|
||||
if (dy < -th) {
|
||||
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeUp - 1], KeyInputFlags::DOWN);
|
||||
swipeUpReleased_ = false;
|
||||
@@ -1274,7 +1309,7 @@ void GestureGamepad::Update() {
|
||||
swipeUpReleased_ = true;
|
||||
}
|
||||
}
|
||||
if (GetZone().iSwipeDown != 0) {
|
||||
if (ValidGestureKeyConfig(GetZone().iSwipeDown)) {
|
||||
if (dy > th) {
|
||||
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeDown - 1], KeyInputFlags::DOWN);
|
||||
swipeDownReleased_ = false;
|
||||
|
||||
@@ -5,46 +5,6 @@
|
||||
#include "PPSSPP_UWPMain.h"
|
||||
|
||||
namespace UWP {
|
||||
struct Touch {
|
||||
bool inUse = false;
|
||||
unsigned uid;
|
||||
};
|
||||
|
||||
class TouchMapper {
|
||||
public:
|
||||
int TouchId(unsigned touch) {
|
||||
for (int touchIx = 0; touchIx < maxTouches; touchIx++)
|
||||
if (touches[touchIx].inUse && touches[touchIx].uid == touch)
|
||||
return touchIx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AddNewTouch(unsigned touch) {
|
||||
for (int touchIx = 0; touchIx < maxTouches; touchIx++) {
|
||||
if (!touches[touchIx].inUse) {
|
||||
touches[touchIx].inUse = true;
|
||||
touches[touchIx].uid = touch;
|
||||
return touchIx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RemoveTouch(unsigned touch) {
|
||||
for (int touchIx = 0; touchIx < maxTouches; touchIx++) {
|
||||
if (touches[touchIx].inUse && touches[touchIx].uid == touch) {
|
||||
touches[touchIx].inUse = false;
|
||||
return touchIx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { maxTouches = 11 };
|
||||
Touch touches[maxTouches]{};
|
||||
};
|
||||
|
||||
// Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events.
|
||||
struct App : winrt::implements<App, winrt::Windows::ApplicationModel::Core::IFrameworkView> {
|
||||
public:
|
||||
|
||||
@@ -1395,6 +1395,8 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNI
|
||||
} else if (prm == "local_network") {
|
||||
INFO_LOG(Log::System, "LOCAL NETWORK PERMISSION: DENIED");
|
||||
permissions[SYSTEM_PERMISSION_LOCAL_NETWORK] = PERMISSION_STATUS_DENIED;
|
||||
} else {
|
||||
WARN_LOG(Log::System, "UNKNOWN PERMISSION GRANTED: %s", prm.c_str());
|
||||
}
|
||||
} else if (msg == "permission_granted") {
|
||||
if (prm == "storage") {
|
||||
@@ -1403,6 +1405,8 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessageFromJava(JNI
|
||||
} else if (prm == "local_network") {
|
||||
INFO_LOG(Log::System, "LOCAL NETWORK PERMISSION: GRANTED");
|
||||
permissions[SYSTEM_PERMISSION_LOCAL_NETWORK] = PERMISSION_STATUS_GRANTED;
|
||||
} else {
|
||||
WARN_LOG(Log::System, "UNKNOWN PERMISSION GRANTED: %s", prm.c_str());
|
||||
}
|
||||
System_PostUIMessage(UIMessage::PERMISSION_GRANTED, prm);
|
||||
} else if (msg == "sustained_perf_supported") {
|
||||
|
||||
@@ -375,7 +375,11 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// Initialize audio classes. Do this here since detectOptimalAudioSettings()
|
||||
// needs audioManager
|
||||
this.audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
this.audioFocusChangeListener = new AudioFocusChangeListener();
|
||||
if (this.audioManager != null) {
|
||||
this.audioFocusChangeListener = new AudioFocusChangeListener();
|
||||
} else {
|
||||
Log.e(TAG, "Failed to get audio manager, likely not supported on this device.");
|
||||
}
|
||||
|
||||
// Get the optimal buffer sz
|
||||
detectOptimalAudioSettings();
|
||||
@@ -1120,7 +1124,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// instantiate NativeAudioPlayer
|
||||
public static void updateAudioFocus(AudioManager audioManager, AudioFocusChangeListener focusChangeListener) {
|
||||
if (audioManager == null) {
|
||||
Log.w(TAG, "Couldn't update audio focus, audio manager null");
|
||||
// Not supported on this device, we logged in init.
|
||||
return;
|
||||
}
|
||||
if (NativeApp.queryConfig("audioMixWithOthers").equals("0")) {
|
||||
|
||||
Reference in new issue
Block a user