Better evdev joystick axis scaling (#3202)

Fix evdev scaling when the minimum value is <0
Declare a trigger as pressed as long as any value >0 is given
This commit is contained in:
Ryan Gonzalez 2017-08-15 14:14:13 -05:00 committed by Ivan
parent 956117a74f
commit 6d14583f28
2 changed files with 37 additions and 24 deletions

View File

@ -34,7 +34,6 @@ void evdev_joystick_handler::Init(const u32 max_connect)
g_evdev_joystick_config.load(); g_evdev_joystick_config.load();
needscale = static_cast<bool>(g_evdev_joystick_config.needscale);
axistrigger = static_cast<bool>(g_evdev_joystick_config.axistrigger); axistrigger = static_cast<bool>(g_evdev_joystick_config.axistrigger);
revaxis.emplace_back(g_evdev_joystick_config.lxreverse); revaxis.emplace_back(g_evdev_joystick_config.lxreverse);
@ -173,12 +172,16 @@ bool evdev_joystick_handler::try_open_dev(u32 index)
int axes=0; int axes=0;
for (int i=ABS_X; i<=ABS_RZ; i++) for (int i=ABS_X; i<=ABS_RZ; i++)
{ {
// Skip ABS_Z and ABS_RZ on controllers where it's used for the triggers.
if (axistrigger && (i == ABS_Z || i == ABS_RZ)) continue;
if (libevdev_has_event_code(dev, EV_ABS, i)) if (libevdev_has_event_code(dev, EV_ABS, i))
{ {
LOG_NOTICE(GENERAL, "Joystick #%d has axis %d as %d", index, i, axes); LOG_NOTICE(GENERAL, "Joystick #%d has axis %d as %d", index, i, axes);
axis_ranges[i].first = libevdev_get_abs_minimum(dev, i);
axis_ranges[i].second = libevdev_get_abs_maximum(dev, i);
// Skip ABS_Z and ABS_RZ on controllers where it's used for the triggers.
if (axistrigger && (i == ABS_Z || i == ABS_RZ)) continue;
joy_axis_maps[index][i - ABS_X] = axes++; joy_axis_maps[index][i - ABS_X] = axes++;
} }
} }
@ -220,6 +223,28 @@ void evdev_joystick_handler::Close()
} }
} }
int evdev_joystick_handler::scale_axis(int axis, int value)
{
auto range = axis_ranges[axis];
// Check if scaling is needed.
if (range.first != 0 || range.second != 255)
{
if (range.first < 0)
{
// Move the ranges up to make the following calculation actually *work*
value += -range.first;
range.second += -range.first;
range.first = 0;
}
return (static_cast<float>(value - range.first) / range.second) * 255;
}
else
{
return value;
}
}
void evdev_joystick_handler::thread_func() void evdev_joystick_handler::thread_func()
{ {
while (active) while (active)
@ -331,7 +356,7 @@ void evdev_joystick_handler::thread_func()
} }
else if (axistrigger && (evt.code == ABS_Z || evt.code == ABS_RZ)) else if (axistrigger && (evt.code == ABS_Z || evt.code == ABS_RZ))
{ {
// For Xbox 360 controllers, a third axis represent the left/right triggers. // For Xbox controllers, a third axis represent the left/right triggers.
int which_trigger=0; int which_trigger=0;
if (evt.code == ABS_Z) if (evt.code == ABS_Z)
@ -356,8 +381,10 @@ void evdev_joystick_handler::thread_func()
LOG_ERROR(GENERAL, "Joystick #%d's pad has no trigger %d", i, which_trigger); LOG_ERROR(GENERAL, "Joystick #%d's pad has no trigger %d", i, which_trigger);
break; break;
} }
which_button->m_pressed = evt.value == 255;
which_button->m_value = evt.value; int value = scale_axis(evt.code, evt.value);
which_button->m_pressed = value > 0;
which_button->m_value = value;
} }
else if (evt.code >= ABS_X && evt.code <= ABS_RZ) else if (evt.code >= ABS_X && evt.code <= ABS_RZ)
{ {
@ -369,22 +396,7 @@ void evdev_joystick_handler::thread_func()
break; break;
} }
auto& stick = pad.m_sticks[axis]; pad.m_sticks[axis].m_value = scale_axis(evt.code, evt.value);
int value = evt.value;
if (needscale)
{
// Scale from the -32768...32768 range to the 0...256 range.
value = (value / 256) + 128;
}
if (revaxis[axis])
{
value = 256 - value;
}
stick.m_value = value;
} }
break; break;
default: default:

View File

@ -44,7 +44,6 @@ struct evdev_joystick_config final : cfg::node
cfg::_bool lxreverse{this, "Reverse left stick X axis", false}; cfg::_bool lxreverse{this, "Reverse left stick X axis", false};
cfg::_bool lyreverse{this, "Reverse left stick Y axis", false}; cfg::_bool lyreverse{this, "Reverse left stick Y axis", false};
cfg::_bool needscale{this, "Axis scaling", true};
cfg::_bool axistrigger{this, "Z axis triggers", true}; cfg::_bool axistrigger{this, "Z axis triggers", true};
bool load() bool load()
@ -76,6 +75,7 @@ public:
private: private:
void update_devs(); void update_devs();
bool try_open_dev(u32 index); bool try_open_dev(u32 index);
int scale_axis(int axis, int value);
void thread_func(); void thread_func();
std::unique_ptr<std::thread> joy_thread; std::unique_ptr<std::thread> joy_thread;
@ -85,6 +85,7 @@ private:
std::vector<std::vector<int>> joy_button_maps; std::vector<std::vector<int>> joy_button_maps;
std::vector<std::vector<int>> joy_axis_maps; std::vector<std::vector<int>> joy_axis_maps;
std::vector<int> joy_hat_ids; std::vector<int> joy_hat_ids;
bool needscale, axistrigger; bool axistrigger;
std::map<int, std::pair<int, int>> axis_ranges;
std::vector<bool> revaxis; std::vector<bool> revaxis;
}; };