mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-12-11 12:25:50 +00:00
Linux: Add an evdev based controller backend, to replace SDL.
This commit is contained in:
parent
9a244f07fa
commit
2721fdf8a9
@ -513,6 +513,19 @@ if(USE_EGL)
|
|||||||
add_definitions(-DUSE_EGL=1)
|
add_definitions(-DUSE_EGL=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
|
include(FindLibudev OPTIONAL)
|
||||||
|
include(FindLibevdev OPTIONAL)
|
||||||
|
if(LIBUDEV_FOUND AND LIBEVDEV_FOUND)
|
||||||
|
message("libevdev/libudev found, enabling evdev controller backend")
|
||||||
|
add_definitions(-DHAVE_LIBUDEV=1)
|
||||||
|
add_definitions(-DHAVE_LIBEVDEV=1)
|
||||||
|
include_directories(${LIBUDEV_INCLUDE_DIR} ${LIBEVDEV_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
message("Could find libevdev/libudev, disabling evdev controller backend")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Setup include directories (and make sure they are preferred over the Externals)
|
# Setup include directories (and make sure they are preferred over the Externals)
|
||||||
#
|
#
|
||||||
|
33
CMakeTests/FindLibevdev.cmake
Normal file
33
CMakeTests/FindLibevdev.cmake
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# - Try to find libevdev
|
||||||
|
# Once done this will define
|
||||||
|
# LIBEVDEV_FOUND - System has libevdev
|
||||||
|
# LIBEVDEV_INCLUDE_DIRS - The libevdev include directories
|
||||||
|
# LIBEVDEV_LIBRARIES - The libraries needed to use libevdev
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(PC_LIBEVDEV QUIET libevdev)
|
||||||
|
|
||||||
|
FIND_PATH(
|
||||||
|
LIBEVDEV_INCLUDE_DIR libevdev/libevdev.h
|
||||||
|
HINTS ${PC_LIBEVDEV_INCLUDEDIR} ${PC_LIBEVDEV_INCLUDE_DIRS}
|
||||||
|
/usr/include
|
||||||
|
/usr/local/include
|
||||||
|
${LIBEVDEV_PATH_INCLUDES}
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(
|
||||||
|
LIBEVDEV_LIBRARY
|
||||||
|
NAMES evdev libevdev
|
||||||
|
HINTS ${PC_LIBEVDEV_LIBDIR} ${PC_LIBEVDEV_LIBRARY_DIRS}
|
||||||
|
PATHS ${ADDITIONAL_LIBRARY_PATHS}
|
||||||
|
${LIBEVDEV_PATH_LIB}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBEVDEV_LIBRARIES ${LIBEVDEV_LIBRARY} )
|
||||||
|
set(LIBEVDEV_INCLUDE_DIRS ${LIBEVDEV_INCLUDE_DIR} )
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(libevdev DEFAULT_MSG
|
||||||
|
LIBEVDEV_LIBRARY LIBEVDEV_INCLUDE_DIR)
|
||||||
|
|
||||||
|
mark_as_advanced(LIBEVDEV_INCLUDE_DIR LIBEVDEV_LIBRARY )
|
28
CMakeTests/FindLibudev.cmake
Normal file
28
CMakeTests/FindLibudev.cmake
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# - Try to find LIBUDEV
|
||||||
|
# Once done this will define
|
||||||
|
# LIBUDEV_FOUND - System has LIBUDEV
|
||||||
|
# LIBUDEV_INCLUDE_DIRS - The LIBUDEV include directories
|
||||||
|
# LIBUDEV_LIBRARIES - The libraries needed to use LIBUDEV
|
||||||
|
|
||||||
|
FIND_PATH(
|
||||||
|
LIBUDEV_INCLUDE_DIR libudev.h
|
||||||
|
/usr/include
|
||||||
|
/usr/local/include
|
||||||
|
${LIBUDEV_PATH_INCLUDES}
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(
|
||||||
|
LIBUDEV_LIBRARY
|
||||||
|
NAMES udev libudev
|
||||||
|
PATHS ${ADDITIONAL_LIBRARY_PATHS}
|
||||||
|
${LIBUDEV_PATH_LIB}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBUDEV_LIBRARIES ${LIBUDEV_LIBRARY} )
|
||||||
|
set(LIBUDEV_INCLUDE_DIRS ${LIBUDEV_INCLUDE_DIR} )
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(LIBUDEV DEFAULT_MSG
|
||||||
|
LIBUDEV_LIBRARY LIBUDEV_INCLUDE_DIR)
|
||||||
|
|
||||||
|
mark_as_advanced(LIBUDEV_INCLUDE_DIR LIBUDEV_LIBRARY )
|
@ -37,6 +37,11 @@ elseif(ANDROID)
|
|||||||
ControllerInterface/Android/Android.cpp)
|
ControllerInterface/Android/Android.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LIBEVDEV_FOUND AND LIBUDEV_FOUND)
|
||||||
|
set(SRCS ${SRCS} ControllerInterface/evdev/evdev.cpp)
|
||||||
|
set(LIBS ${LIBS} ${LIBEVDEV_LIBRARY} ${LIBUDEV_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(SDL_FOUND OR SDL2_FOUND)
|
if(SDL_FOUND OR SDL2_FOUND)
|
||||||
set(SRCS ${SRCS} ControllerInterface/SDL/SDL.cpp)
|
set(SRCS ${SRCS} ControllerInterface/SDL/SDL.cpp)
|
||||||
if (SDL2_FOUND)
|
if (SDL2_FOUND)
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
#ifdef CIFACE_USE_ANDROID
|
#ifdef CIFACE_USE_ANDROID
|
||||||
#include "InputCommon/ControllerInterface/Android/Android.h"
|
#include "InputCommon/ControllerInterface/Android/Android.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CIFACE_USE_EVDEV
|
||||||
|
#include "InputCommon/ControllerInterface/evdev/evdev.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace ciface::ExpressionParser;
|
using namespace ciface::ExpressionParser;
|
||||||
|
|
||||||
@ -69,6 +72,9 @@ void ControllerInterface::Initialize(void* const hwnd)
|
|||||||
#ifdef CIFACE_USE_ANDROID
|
#ifdef CIFACE_USE_ANDROID
|
||||||
ciface::Android::Init(m_devices);
|
ciface::Android::Init(m_devices);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CIFACE_USE_EVDEV
|
||||||
|
ciface::evdev::Init(m_devices);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_is_init = true;
|
m_is_init = true;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,9 @@
|
|||||||
#if defined(HAVE_SDL) && HAVE_SDL
|
#if defined(HAVE_SDL) && HAVE_SDL
|
||||||
#define CIFACE_USE_SDL
|
#define CIFACE_USE_SDL
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_LIBEVDEV) && defined(HAVE_LIBUDEV)
|
||||||
|
#define CIFACE_USE_EVDEV
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// ControllerInterface
|
// ControllerInterface
|
||||||
|
264
Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
Normal file
264
Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
// Copyright 2015 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <libudev.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "InputCommon/ControllerInterface/evdev/evdev.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace ciface
|
||||||
|
{
|
||||||
|
namespace evdev
|
||||||
|
{
|
||||||
|
|
||||||
|
void Init(std::vector<Core::Device*> &controllerDevices)
|
||||||
|
{
|
||||||
|
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 (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.
|
||||||
|
evdevDevice* input = new evdevDevice(devnode, num_controllers);
|
||||||
|
|
||||||
|
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_range = libevdev_get_abs_maximum(m_dev, m_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (m_upper)
|
||||||
|
return std::max(0.0, double(value) / double(m_range) - 0.5) * 2.0;
|
||||||
|
else
|
||||||
|
return (0.5 - std::min(0.5, double(value) / double(m_range))) * 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 (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));
|
||||||
|
}
|
||||||
|
else if (m_id != -1) // delete the effect (which also stops it)
|
||||||
|
{
|
||||||
|
ioctl(m_id, EVIOCRMFF, m_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
86
Source/Core/InputCommon/ControllerInterface/evdev/evdev.h
Normal file
86
Source/Core/InputCommon/ControllerInterface/evdev/evdev.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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;
|
||||||
|
libevdev* m_dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ForceFeedback : public Core::Device::Output
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string GetName() const override;
|
||||||
|
ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_dev(dev), m_id(-1) { m_fd = libevdev_get_fd(dev); }
|
||||||
|
void SetState(ControlState state) override;
|
||||||
|
private:
|
||||||
|
const u16 m_type;
|
||||||
|
libevdev* m_dev;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user