Merge pull request #5265 from german77/port5509

Port citra-emu/citra#5509 "Look at direction of analog axis travel instead of instantaneous sample"
This commit is contained in:
bunnei 2020-12-30 22:24:30 -08:00 committed by GitHub
commit fb41c82aaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 45 additions and 2 deletions

View File

@ -1030,11 +1030,44 @@ public:
} }
return {}; return {};
} }
[[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const { [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(SDL_Event& event) {
switch (event.type) { switch (event.type) {
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
if (std::abs(event.jaxis.value / 32767.0) < 0.5) { if (!axis_memory.count(event.jaxis.which) ||
!axis_memory[event.jaxis.which].count(event.jaxis.axis)) {
axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value;
axis_event_count[event.jaxis.which][event.jaxis.axis] = 1;
break; break;
} else {
axis_event_count[event.jaxis.which][event.jaxis.axis]++;
// The joystick and axis exist in our map if we take this branch, so no checks
// needed
if (std::abs(
(event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) /
32767.0) < 0.5) {
break;
} else {
if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 &&
IsAxisAtPole(event.jaxis.value) &&
IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) {
// If we have exactly two events and both are near a pole, this is
// likely a digital input masquerading as an analog axis; Instead of
// trying to look at the direction the axis travelled, assume the first
// event was press and the second was release; This should handle most
// digital axes while deferring to the direction of travel for analog
// axes
event.jaxis.value = static_cast<Sint16>(
std::copysign(32767, axis_memory[event.jaxis.which][event.jaxis.axis]));
} else {
// There are more than two events, so this is likely a true analog axis,
// check the direction it travelled
event.jaxis.value = static_cast<Sint16>(std::copysign(
32767,
event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]));
}
axis_memory.clear();
axis_event_count.clear();
}
} }
[[fallthrough]]; [[fallthrough]];
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
@ -1043,6 +1076,16 @@ public:
} }
return std::nullopt; return std::nullopt;
} }
private:
// Determine whether an axis value is close to an extreme or center
// Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per
// axis, which is why the center must be considered a pole
bool IsAxisAtPole(int16_t value) const {
return std::abs(value) >= 32767 || std::abs(value) < 327;
}
std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, int16_t>> axis_memory;
std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, uint32_t>> axis_event_count;
}; };
class SDLMotionPoller final : public SDLPoller { class SDLMotionPoller final : public SDLPoller {