summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp')
-rw-r--r--Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp468
1 files changed, 232 insertions, 236 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
index d88a44b7ef..7a6ba50713 100644
--- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
@@ -11,295 +11,291 @@
#include "Common/Logging/Log.h"
#include "InputCommon/ControllerInterface/evdev/evdev.h"
-
namespace ciface
{
namespace evdev
{
-
static std::string GetName(const std::string& devnode)
{
- int fd = open(devnode.c_str(), O_RDWR|O_NONBLOCK);
- libevdev* dev = nullptr;
- int ret = libevdev_new_from_fd(fd, &dev);
- if (ret != 0)
- {
- close(fd);
- return std::string();
- }
- std::string res = libevdev_get_name(dev);
- libevdev_free(dev);
- close(fd);
- return res;
+ int fd = open(devnode.c_str(), O_RDWR | O_NONBLOCK);
+ libevdev* dev = nullptr;
+ int ret = libevdev_new_from_fd(fd, &dev);
+ if (ret != 0)
+ {
+ close(fd);
+ return std::string();
+ }
+ std::string res = libevdev_get_name(dev);
+ libevdev_free(dev);
+ close(fd);
+ return res;
}
-void Init(std::vector<Core::Device*> &controllerDevices)
+void Init(std::vector<Core::Device*>& controllerDevices)
{
- // this is used to number the joysticks
- // multiple joysticks with the same name shall get unique ids starting at 0
- std::map<std::string, int> name_counts;
-
- int num_controllers = 0;
-
- // We use Udev to find any devices. In the future this will allow for hotplugging.
- // But for now it is essentially iterating over /dev/input/event0 to event31. However if the
- // naming scheme is ever updated in the future, this *should* be forwards compatable.
-
- struct udev* udev = udev_new();
- _assert_msg_(PAD, udev != 0, "Couldn't initilize libudev.");
-
- // List all input devices
- udev_enumerate* enumerate = udev_enumerate_new(udev);
- udev_enumerate_add_match_subsystem(enumerate, "input");
- udev_enumerate_scan_devices(enumerate);
- udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
-
- // Iterate over all input devices
- udev_list_entry* dev_list_entry;
- udev_list_entry_foreach(dev_list_entry, devices)
- {
- const char* path = udev_list_entry_get_name(dev_list_entry);
-
- udev_device* dev = udev_device_new_from_syspath(udev, path);
-
- const char* devnode = udev_device_get_devnode(dev);
- // We only care about devices which we have read/write access to.
- if (devnode && access(devnode, W_OK) == 0)
- {
- // Unfortunately udev gives us no way to filter out the non event device interfaces.
- // So we open it and see if it works with evdev ioctls or not.
- std::string name = GetName(devnode);
- evdevDevice* input = new evdevDevice(devnode, name_counts[name]++);
-
- if (input->IsInteresting())
- {
- controllerDevices.push_back(input);
- num_controllers++;
- }
- else
- {
- // Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis.
- delete input;
- }
- }
- udev_device_unref(dev);
- }
- udev_enumerate_unref(enumerate);
- udev_unref(udev);
+ // this is used to number the joysticks
+ // multiple joysticks with the same name shall get unique ids starting at 0
+ std::map<std::string, int> name_counts;
+
+ int num_controllers = 0;
+
+ // We use Udev to find any devices. In the future this will allow for hotplugging.
+ // But for now it is essentially iterating over /dev/input/event0 to event31. However if the
+ // naming scheme is ever updated in the future, this *should* be forwards compatable.
+
+ struct udev* udev = udev_new();
+ _assert_msg_(PAD, udev != 0, "Couldn't initilize libudev.");
+
+ // List all input devices
+ udev_enumerate* enumerate = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(enumerate, "input");
+ udev_enumerate_scan_devices(enumerate);
+ udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
+
+ // Iterate over all input devices
+ udev_list_entry* dev_list_entry;
+ udev_list_entry_foreach(dev_list_entry, devices)
+ {
+ const char* path = udev_list_entry_get_name(dev_list_entry);
+
+ udev_device* dev = udev_device_new_from_syspath(udev, path);
+
+ const char* devnode = udev_device_get_devnode(dev);
+ // We only care about devices which we have read/write access to.
+ if (devnode && access(devnode, W_OK) == 0)
+ {
+ // Unfortunately udev gives us no way to filter out the non event device interfaces.
+ // So we open it and see if it works with evdev ioctls or not.
+ std::string name = GetName(devnode);
+ evdevDevice* input = new evdevDevice(devnode, name_counts[name]++);
+
+ if (input->IsInteresting())
+ {
+ controllerDevices.push_back(input);
+ num_controllers++;
+ }
+ else
+ {
+ // Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis.
+ delete input;
+ }
+ }
+ udev_device_unref(dev);
+ }
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
}
-evdevDevice::evdevDevice(const std::string &devnode, int id) : m_devfile(devnode), m_id(id)
+evdevDevice::evdevDevice(const std::string& devnode, int id) : m_devfile(devnode), m_id(id)
{
- // The device file will be read on one of the main threads, so we open in non-blocking mode.
- m_fd = open(devnode.c_str(), O_RDWR|O_NONBLOCK);
- int ret = libevdev_new_from_fd(m_fd, &m_dev);
-
- if (ret != 0)
- {
- // This useally fails because the device node isn't an evdev device, such as /dev/input/js0
- m_initialized = false;
- close(m_fd);
- return;
- }
-
- m_name = libevdev_get_name(m_dev);
-
- // Controller buttons (and keyboard keys)
- int num_buttons = 0;
- for (int key = 0; key < KEY_MAX; key++)
- if (libevdev_has_event_code(m_dev, EV_KEY, key))
- AddInput(new Button(num_buttons++, key, m_dev));
-
- // Absolute axis (thumbsticks)
- int num_axis = 0;
- for (int axis = 0; axis < 0x100; axis++)
- if (libevdev_has_event_code(m_dev, EV_ABS, axis))
- {
- AddAnalogInputs(new Axis(num_axis, axis, false, m_dev),
- new Axis(num_axis, axis, true, m_dev));
- num_axis++;
- }
-
- // Force feedback
- if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC))
- {
- for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN})
- if (libevdev_has_event_code(m_dev, EV_FF, type))
- AddOutput(new ForceFeedback(type, m_dev));
- }
- if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE))
- {
- AddOutput(new ForceFeedback(FF_RUMBLE, m_dev));
- }
-
- // TODO: Add leds as output devices
-
- m_initialized = true;
- m_interesting = num_axis >= 2 || num_buttons >= 8;
+ // The device file will be read on one of the main threads, so we open in non-blocking mode.
+ m_fd = open(devnode.c_str(), O_RDWR | O_NONBLOCK);
+ int ret = libevdev_new_from_fd(m_fd, &m_dev);
+
+ if (ret != 0)
+ {
+ // This useally fails because the device node isn't an evdev device, such as /dev/input/js0
+ m_initialized = false;
+ close(m_fd);
+ return;
+ }
+
+ m_name = libevdev_get_name(m_dev);
+
+ // Controller buttons (and keyboard keys)
+ int num_buttons = 0;
+ for (int key = 0; key < KEY_MAX; key++)
+ if (libevdev_has_event_code(m_dev, EV_KEY, key))
+ AddInput(new Button(num_buttons++, key, m_dev));
+
+ // Absolute axis (thumbsticks)
+ int num_axis = 0;
+ for (int axis = 0; axis < 0x100; axis++)
+ if (libevdev_has_event_code(m_dev, EV_ABS, axis))
+ {
+ AddAnalogInputs(new Axis(num_axis, axis, false, m_dev),
+ new Axis(num_axis, axis, true, m_dev));
+ num_axis++;
+ }
+
+ // Force feedback
+ if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC))
+ {
+ for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN})
+ if (libevdev_has_event_code(m_dev, EV_FF, type))
+ AddOutput(new ForceFeedback(type, m_dev));
+ }
+ if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE))
+ {
+ AddOutput(new ForceFeedback(FF_RUMBLE, m_dev));
+ }
+
+ // TODO: Add leds as output devices
+
+ m_initialized = true;
+ m_interesting = num_axis >= 2 || num_buttons >= 8;
}
evdevDevice::~evdevDevice()
{
- if (m_initialized)
- {
- libevdev_free(m_dev);
- close(m_fd);
- }
+ if (m_initialized)
+ {
+ libevdev_free(m_dev);
+ close(m_fd);
+ }
}
void evdevDevice::UpdateInput()
{
- // Run through all evdev events
- // libevdev will keep track of the actual controller state internally which can be queried
- // later with libevdev_fetch_event_value()
- input_event ev;
- int rc = LIBEVDEV_READ_STATUS_SUCCESS;
- do
- {
- if (rc == LIBEVDEV_READ_STATUS_SYNC)
- rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
- else
- rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
- } while (rc >= 0);
+ // Run through all evdev events
+ // libevdev will keep track of the actual controller state internally which can be queried
+ // later with libevdev_fetch_event_value()
+ input_event ev;
+ int rc = LIBEVDEV_READ_STATUS_SUCCESS;
+ do
+ {
+ if (rc == LIBEVDEV_READ_STATUS_SYNC)
+ rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
+ else
+ rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+ } while (rc >= 0);
}
-
std::string evdevDevice::Button::GetName() const
{
- // Buttons below 0x100 are mostly keyboard keys, and the names make sense
- if (m_code < 0x100)
- {
- const char* name = libevdev_event_code_get_name(EV_KEY, m_code);
- if (name)
- return std::string(name);
- }
- // But controllers use codes above 0x100, and the standard label often doesn't match.
- // We are better off with Button 0 and so on.
- return "Button " + std::to_string(m_index);
+ // Buttons below 0x100 are mostly keyboard keys, and the names make sense
+ if (m_code < 0x100)
+ {
+ const char* name = libevdev_event_code_get_name(EV_KEY, m_code);
+ if (name)
+ return std::string(name);
+ }
+ // But controllers use codes above 0x100, and the standard label often doesn't match.
+ // We are better off with Button 0 and so on.
+ return "Button " + std::to_string(m_index);
}
ControlState evdevDevice::Button::GetState() const
{
- int value = 0;
- libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value);
- return value;
+ int value = 0;
+ libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value);
+ return value;
}
-evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) :
- m_code(code), m_index(index), m_upper(upper), m_dev(dev)
+evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev)
+ : m_code(code), m_index(index), m_upper(upper), m_dev(dev)
{
- m_min = libevdev_get_abs_minimum(m_dev, m_code);
- m_range = libevdev_get_abs_maximum(m_dev, m_code) + abs(m_min);
+ m_min = libevdev_get_abs_minimum(m_dev, m_code);
+ m_range = libevdev_get_abs_maximum(m_dev, m_code) + abs(m_min);
}
std::string evdevDevice::Axis::GetName() const
{
- return "Axis " + std::to_string(m_index) + (m_upper ? "+" : "-");
+ return "Axis " + std::to_string(m_index) + (m_upper ? "+" : "-");
}
ControlState evdevDevice::Axis::GetState() const
{
- int value = 0;
- libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value);
+ int value = 0;
+ libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value);
- // Value from 0.0 to 1.0
- ControlState fvalue = double(value - m_min) / double(m_range);
+ // Value from 0.0 to 1.0
+ ControlState fvalue = double(value - m_min) / double(m_range);
- // Split into two axis, each covering half the range from 0.0 to 1.0
- if (m_upper)
- return std::max(0.0, fvalue - 0.5) * 2.0;
- else
- return (0.5 - std::min(0.5, fvalue)) * 2.0;
+ // Split into two axis, each covering half the range from 0.0 to 1.0
+ if (m_upper)
+ return std::max(0.0, fvalue - 0.5) * 2.0;
+ else
+ return (0.5 - std::min(0.5, fvalue)) * 2.0;
}
std::string evdevDevice::ForceFeedback::GetName() const
{
- // We have some default names.
- switch (m_type)
- {
- case FF_SINE:
- return "Sine";
- case FF_TRIANGLE:
- return "Triangle";
- case FF_SQUARE:
- return "Square";
- case FF_RUMBLE:
- return "LeftRight";
- default:
- {
- const char* name = libevdev_event_code_get_name(EV_FF, m_type);
- if (name)
- return std::string(name);
- return "Unknown";
- }
- }
+ // We have some default names.
+ switch (m_type)
+ {
+ case FF_SINE:
+ return "Sine";
+ case FF_TRIANGLE:
+ return "Triangle";
+ case FF_SQUARE:
+ return "Square";
+ case FF_RUMBLE:
+ return "LeftRight";
+ default:
+ {
+ const char* name = libevdev_event_code_get_name(EV_FF, m_type);
+ if (name)
+ return std::string(name);
+ return "Unknown";
+ }
+ }
}
void evdevDevice::ForceFeedback::SetState(ControlState state)
{
- // libevdev doesn't have nice helpers for forcefeedback
- // we will use the file descriptors directly.
-
- if (m_id != -1) // delete the previous effect (which also stops it)
- {
- ioctl(m_fd, EVIOCRMFF, m_id);
- m_id = -1;
- }
-
- if (state > 0) // Upload and start an effect.
- {
- ff_effect effect;
-
- effect.id = -1;
- effect.direction = 0; // down
- effect.replay.length = 500; // 500ms
- effect.replay.delay = 0;
- effect.trigger.button = 0; // don't trigger on button press
- effect.trigger.interval = 0;
-
- // This is the the interface that XInput uses, with 2 motors of differing sizes/frequencies that
- // are controlled seperatally
- if (m_type == FF_RUMBLE)
- {
- effect.type = FF_RUMBLE;
- // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller
- effect.u.rumble.strong_magnitude = u16(state * 0x4000);
- effect.u.rumble.weak_magnitude = u16(state * 0xFFFF);
- }
- else // FF_PERIODIC, a more generic interface.
- {
- effect.type = FF_PERIODIC;
- effect.u.periodic.waveform = m_type;
- effect.u.periodic.phase = 0x7fff; // 180 degrees
- effect.u.periodic.offset = 0;
- effect.u.periodic.period = 10;
- effect.u.periodic.magnitude = s16(state * 0x7FFF);
- effect.u.periodic.envelope.attack_length = 0; // no attack
- effect.u.periodic.envelope.attack_level = 0;
- effect.u.periodic.envelope.fade_length = 0;
- effect.u.periodic.envelope.fade_level = 0;
- }
-
- ioctl(m_fd, EVIOCSFF, &effect);
- m_id = effect.id;
-
- input_event play;
- play.type = EV_FF;
- play.code = m_id;
- play.value = 1;
-
- write(m_fd, (const void*) &play, sizeof(play));
- }
+ // libevdev doesn't have nice helpers for forcefeedback
+ // we will use the file descriptors directly.
+
+ if (m_id != -1) // delete the previous effect (which also stops it)
+ {
+ ioctl(m_fd, EVIOCRMFF, m_id);
+ m_id = -1;
+ }
+
+ if (state > 0) // Upload and start an effect.
+ {
+ ff_effect effect;
+
+ effect.id = -1;
+ effect.direction = 0; // down
+ effect.replay.length = 500; // 500ms
+ effect.replay.delay = 0;
+ effect.trigger.button = 0; // don't trigger on button press
+ effect.trigger.interval = 0;
+
+ // This is the the interface that XInput uses, with 2 motors of differing sizes/frequencies that
+ // are controlled seperatally
+ if (m_type == FF_RUMBLE)
+ {
+ effect.type = FF_RUMBLE;
+ // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller
+ effect.u.rumble.strong_magnitude = u16(state * 0x4000);
+ effect.u.rumble.weak_magnitude = u16(state * 0xFFFF);
+ }
+ else // FF_PERIODIC, a more generic interface.
+ {
+ effect.type = FF_PERIODIC;
+ effect.u.periodic.waveform = m_type;
+ effect.u.periodic.phase = 0x7fff; // 180 degrees
+ effect.u.periodic.offset = 0;
+ effect.u.periodic.period = 10;
+ effect.u.periodic.magnitude = s16(state * 0x7FFF);
+ effect.u.periodic.envelope.attack_length = 0; // no attack
+ effect.u.periodic.envelope.attack_level = 0;
+ effect.u.periodic.envelope.fade_length = 0;
+ effect.u.periodic.envelope.fade_level = 0;
+ }
+
+ ioctl(m_fd, EVIOCSFF, &effect);
+ m_id = effect.id;
+
+ input_event play;
+ play.type = EV_FF;
+ play.code = m_id;
+ play.value = 1;
+
+ write(m_fd, (const void*)&play, sizeof(play));
+ }
}
evdevDevice::ForceFeedback::~ForceFeedback()
{
- // delete the uploaded effect, so we don't leak it.
- if (m_id != -1)
- {
- ioctl(m_fd, EVIOCRMFF, m_id);
- }
+ // delete the uploaded effect, so we don't leak it.
+ if (m_id != -1)
+ {
+ ioctl(m_fd, EVIOCRMFF, m_id);
+ }
}
-
}
}