diff options
| author | Linktothepast <kostamarino@gmail.com> | 2015-09-28 16:50:35 +0300 |
|---|---|---|
| committer | Linktothepast <kostamarino@gmail.com> | 2015-09-28 16:50:35 +0300 |
| commit | 748be565b8df535ef558e74b38cd0f4d615f8a21 (patch) | |
| tree | b151efee0a87e99125f2401325a9bddecf84fc73 /Source/Core/InputCommon/ControllerInterface | |
| parent | cf17fccdd3093a1b8476b10183b1c4bde36da74d (diff) | |
| parent | ce493b897d6d3735c930a8465cc0c26bbe5feb86 (diff) | |
Merge remote-tracking branch 'dolphin-emu/master' into gameinis
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
14 files changed, 501 insertions, 79 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp index b0539b520f..7cf0f628bd 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp @@ -17,6 +17,10 @@ void Init( std::vector<Core::Device*>& devices ) devices.push_back(new Touchscreen(1)); devices.push_back(new Touchscreen(2)); devices.push_back(new Touchscreen(3)); + devices.push_back(new Touchscreen(4)); + devices.push_back(new Touchscreen(5)); + devices.push_back(new Touchscreen(6)); + devices.push_back(new Touchscreen(7)); } // Touchscreens and stuff @@ -32,11 +36,12 @@ std::string Touchscreen::GetSource() const int Touchscreen::GetId() const { - return 0; + return _padID; } Touchscreen::Touchscreen(int padID) : _padID(padID) { + // GC AddInput(new Button(_padID, ButtonManager::BUTTON_A)); AddInput(new Button(_padID, ButtonManager::BUTTON_B)); AddInput(new Button(_padID, ButtonManager::BUTTON_START)); @@ -53,6 +58,19 @@ Touchscreen::Touchscreen(int padID) AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_C_UP), new Axis(_padID, ButtonManager::STICK_C_DOWN)); AddAnalogInputs(new Axis(_padID, ButtonManager::TRIGGER_L), new Axis(_padID, ButtonManager::TRIGGER_L)); AddAnalogInputs(new Axis(_padID, ButtonManager::TRIGGER_R), new Axis(_padID, ButtonManager::TRIGGER_R)); + + // Wiimote + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_A)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_B)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_MINUS)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_PLUS)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_HOME)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_1)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_2)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_UP)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_DOWN)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_LEFT)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_RIGHT)); } // Buttons and stuff diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 6b8b11fd3a..0631069e16 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -26,6 +26,9 @@ #ifdef CIFACE_USE_ANDROID #include "InputCommon/ControllerInterface/Android/Android.h" #endif +#ifdef CIFACE_USE_EVDEV + #include "InputCommon/ControllerInterface/evdev/evdev.h" +#endif using namespace ciface::ExpressionParser; @@ -69,6 +72,9 @@ void ControllerInterface::Initialize(void* const hwnd) #ifdef CIFACE_USE_ANDROID ciface::Android::Init(m_devices); #endif +#ifdef CIFACE_USE_EVDEV + ciface::evdev::Init(m_devices); +#endif m_is_init = true; } diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index 408a36fefa..3aca18e95c 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -35,6 +35,9 @@ #if defined(HAVE_SDL) && HAVE_SDL #define CIFACE_USE_SDL #endif +#if defined(HAVE_LIBEVDEV) && defined(HAVE_LIBUDEV) + #define CIFACE_USE_EVDEV +#endif // // ControllerInterface diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h index c89ba509d3..3064051101 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h @@ -20,9 +20,9 @@ private: class Button : public Input { public: - std::string GetName() const; - Button(u8 index, const BYTE& button) : m_index(index), m_button(button) {} - ControlState GetState() const; + Button(u8 index, const BYTE& button) : m_button(button), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const BYTE& m_button; const u8 m_index; @@ -31,9 +31,9 @@ private: class Axis : public Input { public: - std::string GetName() const; - Axis(u8 index, const LONG& axis, LONG base, LONG range) : m_index(index), m_axis(axis), m_base(base), m_range(range) {} - ControlState GetState() const; + Axis(u8 index, const LONG& axis, LONG base, LONG range) : m_axis(axis), m_base(base), m_range(range), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const LONG& m_axis; const LONG m_base, m_range; @@ -43,9 +43,9 @@ private: class Hat : public Input { public: - std::string GetName() const; - Hat(u8 index, const DWORD& hat, u8 direction) : m_index(index), m_hat(hat), m_direction(direction) {} - ControlState GetState() const; + Hat(u8 index, const DWORD& hat, u8 direction) : m_hat(hat), m_direction(direction), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const DWORD& m_hat; const u8 m_index, m_direction; @@ -57,9 +57,9 @@ public: Joystick(const LPDIRECTINPUTDEVICE8 device, const unsigned int index); ~Joystick(); - std::string GetName() const; - int GetId() const; - std::string GetSource() const; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; private: const LPDIRECTINPUTDEVICE8 m_device; diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h index db4d363df0..14d885ff94 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h @@ -32,9 +32,9 @@ private: class Key : public Input { public: - std::string GetName() const; - Key(u8 index, const BYTE& key) : m_index(index), m_key(key) {} - ControlState GetState() const; + Key(u8 index, const BYTE& key) : m_key(key), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const BYTE& m_key; const u8 m_index; @@ -43,9 +43,9 @@ private: class Button : public Input { public: - std::string GetName() const; - Button(u8 index, const BYTE& button) : m_index(index), m_button(button) {} - ControlState GetState() const; + Button(u8 index, const BYTE& button) : m_button(button), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const BYTE& m_button; const u8 m_index; @@ -54,9 +54,9 @@ private: class Axis : public Input { public: - std::string GetName() const; - Axis(u8 index, const LONG& axis, LONG range) : m_index(index), m_axis(axis), m_range(range) {} - ControlState GetState() const; + Axis(u8 index, const LONG& axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const LONG& m_axis; const LONG m_range; @@ -66,10 +66,10 @@ private: class Cursor : public Input { public: - std::string GetName() const; - bool IsDetectable() { return false; } - Cursor(u8 index, const ControlState& axis, const bool positive) : m_index(index), m_axis(axis), m_positive(positive) {} - ControlState GetState() const; + Cursor(u8 index, const ControlState& axis, const bool positive) : m_axis(axis), m_index(index), m_positive(positive) {} + std::string GetName() const override; + bool IsDetectable() override { return false; } + ControlState GetState() const override; private: const ControlState& m_axis; const u8 m_index; @@ -82,9 +82,9 @@ public: KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device); ~KeyboardMouse(); - std::string GetName() const; - int GetId() const; - std::string GetSource() const; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; private: const LPDIRECTINPUTDEVICE8 m_kb_device; diff --git a/Source/Core/InputCommon/ControllerInterface/Device.h b/Source/Core/InputCommon/ControllerInterface/Device.h index c27910af5d..7e6172149f 100644 --- a/Source/Core/InputCommon/ControllerInterface/Device.h +++ b/Source/Core/InputCommon/ControllerInterface/Device.h @@ -61,8 +61,6 @@ public: virtual ControlState GetState() const = 0; - bool ShouldHaveInput(); - ControlState GetGatedState() { if (InputGateOn()) diff --git a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp index 9837ea74cb..bcb2c95a96 100644 --- a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp @@ -63,8 +63,6 @@ public: { switch (type) { - case TOK_INVALID: - return "Invalid"; case TOK_DISCARD: return "Discard"; case TOK_EOF: @@ -83,7 +81,11 @@ public: return "+"; case TOK_CONTROL: return "Device(" + (std::string)qualifier + ")"; + case TOK_INVALID: + break; } + + return "Invalid"; } }; @@ -254,22 +256,22 @@ public: ControlExpression(ControlQualifier qualifier_, Device::Control *control_) : qualifier(qualifier_), control(control_) {} - virtual ControlState GetValue() override + ControlState GetValue() override { return control->ToInput()->GetGatedState(); } - virtual void SetValue(ControlState value) override + void SetValue(ControlState value) override { control->ToOutput()->SetGatedState(value); } - virtual int CountNumControls() override + int CountNumControls() override { return 1; } - virtual operator std::string() override + operator std::string() override { return "`" + (std::string)qualifier + "`"; } @@ -289,7 +291,7 @@ public: delete rhs; } - virtual ControlState GetValue() override + ControlState GetValue() override { ControlState lhsValue = lhs->GetValue(); ControlState rhsValue = rhs->GetValue(); @@ -307,7 +309,7 @@ public: } } - virtual void SetValue(ControlState value) override + void SetValue(ControlState value) override { // Don't do anything special with the op we have. // Treat "A & B" the same as "A | B". @@ -315,12 +317,12 @@ public: rhs->SetValue(value); } - virtual int CountNumControls() override + int CountNumControls() override { return lhs->CountNumControls() + rhs->CountNumControls(); } - virtual operator std::string() override + operator std::string() override { return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")"; } @@ -338,7 +340,7 @@ public: delete inner; } - virtual ControlState GetValue() override + ControlState GetValue() override { ControlState value = inner->GetValue(); switch (op) @@ -351,7 +353,7 @@ public: } } - virtual void SetValue(ControlState value) override + void SetValue(ControlState value) override { switch (op) { @@ -364,12 +366,12 @@ public: } } - virtual int CountNumControls() override + int CountNumControls() override { return inner->CountNumControls(); } - virtual operator std::string() override + operator std::string() override { return OpName(op) + "(" + (std::string)(*inner) + ")"; } diff --git a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h index a528c00602..f49198f037 100644 --- a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h +++ b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h @@ -29,10 +29,11 @@ private: class Force : public Output { public: - std::string GetName() const; Force(const std::string& name, LPDIRECTINPUTEFFECT iface); ~Force(); - void SetState(ControlState state); + + std::string GetName() const override; + void SetState(ControlState state) override; void Update(); void Stop(); private: diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h index c0fdec5537..d0ed715130 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h @@ -20,10 +20,10 @@ private: class Button : public Input { public: - std::string GetName() const; Button(IOHIDElementRef element, IOHIDDeviceRef device) : m_element(element), m_device(device) {} - ControlState GetState() const; + std::string GetName() const override; + ControlState GetState() const override; private: const IOHIDElementRef m_element; const IOHIDDeviceRef m_device; @@ -37,9 +37,10 @@ private: positive = 0, negative }; - std::string GetName() const; + Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction dir); - ControlState GetState() const; + std::string GetName() const override; + ControlState GetState() const override; private: const IOHIDElementRef m_element; @@ -60,9 +61,10 @@ private: down, left }; - std::string GetName() const; + Hat(IOHIDElementRef element, IOHIDDeviceRef device, direction dir); - ControlState GetState() const; + std::string GetName() const override; + ControlState GetState() const override; private: const IOHIDElementRef m_element; @@ -75,9 +77,9 @@ public: Joystick(IOHIDDeviceRef device, std::string name, int index); ~Joystick(); - std::string GetName() const; - std::string GetSource() const; - int GetId() const; + std::string GetName() const override; + std::string GetSource() const override; + int GetId() const override; private: const IOHIDDeviceRef m_device; diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h index 4be67a503c..d404f90684 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h @@ -19,9 +19,9 @@ private: class Key : public Input { public: - std::string GetName() const; Key(IOHIDElementRef element, IOHIDDeviceRef device); - ControlState GetState() const; + std::string GetName() const override; + ControlState GetState() const override; private: const IOHIDElementRef m_element; const IOHIDDeviceRef m_device; @@ -31,10 +31,10 @@ private: class Cursor : public Input { public: - std::string GetName() const; - bool IsDetectable() { return false; } Cursor(u8 index, const float& axis, const bool positive) : m_axis(axis), m_index(index), m_positive(positive) {} - ControlState GetState() const; + std::string GetName() const override; + bool IsDetectable() override { return false; } + ControlState GetState() const override; private: const float& m_axis; const u8 m_index; @@ -44,9 +44,9 @@ private: class Button : public Input { public: - std::string GetName() const; Button(u8 index, const unsigned char& button) : m_button(button), m_index(index) {} - ControlState GetState() const; + std::string GetName() const override; + ControlState GetState() const override; private: const unsigned char& m_button; const u8 m_index; diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp index 0e2c0bcad3..1ee374d483 100644 --- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp +++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp @@ -122,7 +122,7 @@ void DeInit() } Device::Device(const XINPUT_CAPABILITIES& caps, u8 index) - : m_index(index), m_subtype(caps.SubType) + : m_subtype(caps.SubType), m_index(index) { ZeroMemory(&m_state_out, sizeof(m_state_out)); diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h index 5dcfb0cee5..59a3f6ff79 100644 --- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h +++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h @@ -32,9 +32,9 @@ private: class Button : public Core::Device::Input { public: - std::string GetName() const; - Button(u8 index, const WORD& buttons) : m_index(index), m_buttons(buttons) {} - ControlState GetState() const; + Button(u8 index, const WORD& buttons) : m_buttons(buttons), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const WORD& m_buttons; u8 m_index; @@ -43,9 +43,9 @@ private: class Axis : public Core::Device::Input { public: - std::string GetName() const; - Axis(u8 index, const SHORT& axis, SHORT range) : m_index(index), m_axis(axis), m_range(range) {} - ControlState GetState() const; + Axis(u8 index, const SHORT& axis, SHORT range) : m_axis(axis), m_range(range), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const SHORT& m_axis; const SHORT m_range; @@ -55,9 +55,9 @@ private: class Trigger : public Core::Device::Input { public: - std::string GetName() const; - Trigger(u8 index, const BYTE& trigger, BYTE range) : m_index(index), m_trigger(trigger), m_range(range) {} - ControlState GetState() const; + Trigger(u8 index, const BYTE& trigger, BYTE range) : m_trigger(trigger), m_range(range), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; private: const BYTE& m_trigger; const BYTE m_range; @@ -67,9 +67,9 @@ private: class Motor : public Core::Device::Output { public: - std::string GetName() const; - Motor(u8 index, Device* parent, WORD &motor, WORD range) : m_index(index), m_parent(parent), m_motor(motor), m_range(range) {} - void SetState(ControlState state); + Motor(u8 index, Device* parent, WORD &motor, WORD range) : m_motor(motor), m_range(range), m_index(index), m_parent(parent) {} + std::string GetName() const override; + void SetState(ControlState state) override; private: WORD& m_motor; const WORD m_range; @@ -82,9 +82,9 @@ public: Device(const XINPUT_CAPABILITIES& capabilities, u8 index); - std::string GetName() const; - int GetId() const; - std::string GetSource() const; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; void UpdateMotors(); diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp new file mode 100644 index 0000000000..d88a44b7ef --- /dev/null +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -0,0 +1,305 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include <fcntl.h> +#include <libudev.h> +#include <map> +#include <unistd.h> + +#include "Common/Assert.h" +#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; +} + +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); +} + +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; +} + +evdevDevice::~evdevDevice() +{ + 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); +} + + +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); +} + +ControlState evdevDevice::Button::GetState() const +{ + 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) +{ + 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 ? "+" : "-"); +} + +ControlState evdevDevice::Axis::GetState() const +{ + 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); + + // 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"; + } + } +} + +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)); + } +} + +evdevDevice::ForceFeedback::~ForceFeedback() +{ + // delete the uploaded effect, so we don't leak it. + if (m_id != -1) + { + ioctl(m_fd, EVIOCRMFF, m_id); + } +} + +} +} diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h new file mode 100644 index 0000000000..5b3c23a466 --- /dev/null +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -0,0 +1,87 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <vector> +#include <libevdev/libevdev.h> + +#include "InputCommon/ControllerInterface/Device.h" + +namespace ciface +{ +namespace evdev +{ + +void Init(std::vector<Core::Device*>& devices); + +class evdevDevice : public Core::Device +{ +private: + class Button : public Core::Device::Input + { + public: + std::string GetName() const override; + Button(u8 index, u16 code, libevdev* dev) : m_index(index), m_code(code), m_dev(dev) {} + ControlState GetState() const override; + private: + const u8 m_index; + const u16 m_code; + libevdev* m_dev; + }; + + class Axis : public Core::Device::Input + { + public: + std::string GetName() const override; + Axis(u8 index, u16 code, bool upper, libevdev* dev); + ControlState GetState() const override; + private: + const u16 m_code; + const u8 m_index; + const bool m_upper; + int m_range; + int m_min; + libevdev* m_dev; + }; + + class ForceFeedback : public Core::Device::Output + { + public: + std::string GetName() const override; + ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_id(-1) { m_fd = libevdev_get_fd(dev); } + ~ForceFeedback(); + void SetState(ControlState state) override; + private: + const u16 m_type; + int m_fd; + int m_id; + }; + +public: + void UpdateInput() override; + + evdevDevice(const std::string &devnode, int id); + ~evdevDevice(); + + std::string GetName() const override { return m_name; } + int GetId() const override { return m_id; } + std::string GetSource() const override { return "evdev"; } + + bool IsInteresting() const { return m_initialized && m_interesting; } + +private: + const std::string m_devfile; + int m_fd; + libevdev* m_dev; + std::string m_name; + const int m_id; + bool m_initialized; + bool m_interesting; +}; + +} + +} |
