Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(input/linux): add support for more virtual input devices #2606

Merged
merged 39 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
5e01ee2
feat: first draft implementing all virtual devices using inputtino
ABeltramo Mar 14, 2024
3ac2177
feat: allow change of virtual device names
ABeltramo Mar 15, 2024
f75ce72
lint: small refactor following review on Github
ABeltramo Mar 19, 2024
464b25a
fix: updated libinputtino
ABeltramo Mar 26, 2024
7cf769f
fix: extra warnings
ABeltramo Mar 27, 2024
bff5ddc
fix: extra warnings
ABeltramo Mar 28, 2024
57d5041
feat: simplified code by using std::visit
ABeltramo Mar 28, 2024
5886418
fix: lint
ABeltramo Mar 28, 2024
8c05513
docs: added uhid required rules
ABeltramo Apr 4, 2024
accee5b
ui: added gamepad override settings in the web UI for Linux
ABeltramo Apr 4, 2024
207b832
refactor: break inputiino into multiple namespaces
Hazer May 29, 2024
29c7ad4
chore: fix lint
Hazer May 29, 2024
3519082
chore: forgot to update
Hazer May 29, 2024
86f51ee
docs: shorter command for udev rule
Hazer May 29, 2024
2b4f704
build: update inputtino
Hazer May 29, 2024
3ba19fc
chore: platform name reorder
Hazer May 29, 2024
7ca10e2
chore: fix wrong gamepad scope
Hazer May 29, 2024
451e293
chore: cpp errors
Hazer May 29, 2024
a11b69c
chore: add todo remove legacy input
Hazer May 30, 2024
e726339
chore: nitpick
Hazer May 30, 2024
51ea29e
build: update inputtino with <algorithm>
Hazer May 30, 2024
d060954
fix: gcc-14 and PS5 gyro/accel
Hazer May 31, 2024
fe01e72
fix: gcc-14 ps5
Hazer May 31, 2024
a996b6b
build(linux): glob import inputtino
Hazer Jun 1, 2024
9923a75
fix: turn Moonlight reported degrees into radians
ABeltramo Jun 1, 2024
637317a
feat: check gamepad status on startup
Hazer Jun 5, 2024
1a3dc35
chore: code review changes
Hazer Jun 7, 2024
380e47d
chore: cannot use directly as bool, must check
Hazer Jun 7, 2024
0f94ae0
lint: use bool operator
ABeltramo Jun 8, 2024
3f4218c
fix: updated inputtino in order to fix support for PS5 Touchpad
ABeltramo Jun 11, 2024
d7a0032
tests(input): create get_mouse_loc for inputtino
Hazer Jun 13, 2024
75ee3cf
chore: try without transformation first
Hazer Jun 13, 2024
f51d584
chore: disable linux mouse test temporarily
Hazer Jun 13, 2024
cdace2b
chore: ifdef don't allow OR operator
Hazer Jun 13, 2024
c338ed2
fix: battery number report, updated inputtino with latest rumble fixes
ABeltramo Jun 13, 2024
9481a6c
fix: updated inputtino with latest Rumble fixes
ABeltramo Jun 14, 2024
3dada2c
fix(cmake): fix libevdev overrides
ReenigneArcher Jun 15, 2024
b727d28
fix: brew manual build of libevdev for inputtino
ABeltramo Jun 15, 2024
920cca6
brew linux updates
ReenigneArcher Jun 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
path = third-party/googletest
url = https://github.com/google/googletest/
branch = v1.14.x
[submodule "third-party/inputtino"]
path = third-party/inputtino
url = https://github.com/games-on-whales/inputtino.git
branch = stable
[submodule "third-party/moonlight-common-c"]
path = third-party/moonlight-common-c
url = https://github.com/moonlight-stream/moonlight-common-c.git
Expand Down
21 changes: 20 additions & 1 deletion cmake/compile_definitions/linux.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,33 @@ if(${SUNSHINE_ENABLE_TRAY} AND ${SUNSHINE_TRAY} EQUAL 0 AND SUNSHINE_REQUIRE_TRA
message(FATAL_ERROR "Tray icon is required")
endif()

if(${SUNSHINE_USE_LEGACY_INPUT}) # TODO: Remove this legacy option after the next stable release
list(APPEND PLATFORM_TARGET_FILES "${CMAKE_SOURCE_DIR}/src/platform/linux/input/legacy_input.cpp")
Hazer marked this conversation as resolved.
Show resolved Hide resolved
else()
# These need to be set before adding the inputtino subdirectory in order for them to be picked up
set(LIBEVDEV_CUSTOM_INCLUDE_DIR "${EVDEV_INCLUDE_DIR}")
set(LIBEVDEV_CUSTOM_LIBRARY "${EVDEV_LIBRARY}")

add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/inputtino")
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES inputtino::libinputtino)
file(GLOB_RECURSE INPUTTINO_SOURCES
${CMAKE_SOURCE_DIR}/src/platform/linux/input/inputtino*.h
${CMAKE_SOURCE_DIR}/src/platform/linux/input/inputtino*.cpp)
list(APPEND PLATFORM_TARGET_FILES ${INPUTTINO_SOURCES})

# build libevdev before the libinputtino target
if(EXTERNAL_PROJECT_LIBEVDEV_USED)
add_dependencies(libinputtino libevdev)
endif()
endif()

list(APPEND PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/linux/publish.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/graphics.h"
"${CMAKE_SOURCE_DIR}/src/platform/linux/graphics.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/misc.h"
"${CMAKE_SOURCE_DIR}/src/platform/linux/misc.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/audio.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/input.cpp"
"${CMAKE_SOURCE_DIR}/third-party/glad/src/egl.c"
"${CMAKE_SOURCE_DIR}/third-party/glad/src/gl.c"
"${CMAKE_SOURCE_DIR}/third-party/glad/include/EGL/eglplatform.h"
Expand Down
3 changes: 3 additions & 0 deletions cmake/dependencies/libevdev_Sunshine.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ else()
endif()

if(EVDEV_INCLUDE_DIR AND EVDEV_LIBRARY)
message(STATUS "Found libevdev library: ${EVDEV_LIBRARY}")
message(STATUS "Found libevdev include directory: ${EVDEV_INCLUDE_DIR}")

include_directories(SYSTEM ${EVDEV_INCLUDE_DIR})
list(APPEND PLATFORM_LIBRARIES ${EVDEV_LIBRARY})
else()
Expand Down
16 changes: 1 addition & 15 deletions cmake/macros/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,11 @@ macro(find_package) # cmake-lint: disable=C0103
string(TOLOWER "${ARGV0}" ARGV0_LOWER)
if(
(("${ARGV0_LOWER}" STREQUAL "boost") AND DEFINED FETCH_CONTENT_BOOST_USED) OR
(("${ARGV0_LOWER}" STREQUAL "libevdev") AND DEFINED FETCH_CONTENT_LIBEVDEV_USED)
(("${ARGV0_LOWER}" STREQUAL "libevdev") AND DEFINED EXTERNAL_PROJECT_LIBEVDEV_USED)
)
# Do nothing, as the package has already been fetched
else()
# Call the original find_package function
_find_package(${ARGV})
endif()
endmacro()

# override pkg_check_modules function
macro(pkg_check_modules) # cmake-lint: disable=C0103
string(TOLOWER "${ARGV0}" ARGV0_LOWER)
if(
(("${ARGV0_LOWER}" STREQUAL "boost") AND DEFINED FETCH_CONTENT_BOOST_USED) OR
(("${ARGV0_LOWER}" STREQUAL "libevdev") AND DEFINED FETCH_CONTENT_LIBEVDEV_USED)
)
# Do nothing, as the package has already been fetched
else()
# Call the original pkg_check_modules function
_pkg_check_modules(${ARGV})
endif()
endmacro()
2 changes: 2 additions & 0 deletions cmake/prep/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ elseif(UNIX) # Linux
"Enable building wayland specific code." ON)
option(SUNSHINE_ENABLE_X11
"Enable X11 grab if available." ON)
option(SUNSHINE_USE_LEGACY_INPUT # TODO: Remove this legacy option after the next stable release
"Use the legacy virtual input implementation." OFF)
endif()
7 changes: 4 additions & 3 deletions docs/source/about/setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,13 @@ Install
The `deb`, `rpm`, `zst`, `Flatpak` and `AppImage` packages should handle these steps automatically.
Third party packages may not.

Sunshine needs access to `uinput` to create mouse and gamepad events.
Sunshine needs access to `uinput` to create mouse and gamepad virtual devices and (optionally) to `uhid`
in order to emulate a PS5 DualSense joypad with Gyro, Acceleration and Touchpad support.

#. Create and reload `udev` rules for uinput.
#. Create and reload `udev` rules for `uinput` and `uhid`.
.. code-block:: bash

echo 'KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"' | \
echo 'KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"\nKERNEL=="uhid", TAG+="uaccess"' | \
sudo tee /etc/udev/rules.d/60-sunshine.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
Expand Down
17 changes: 14 additions & 3 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,8 @@
std::chrono::duration<double> { 1 / 24.9 }, // key_repeat_period

{
platf::supported_gamepads().front().data(),
platf::supported_gamepads().front().size(),
platf::supported_gamepads(nullptr).front().name.data(),
platf::supported_gamepads(nullptr).front().name.size(),
}, // Default gamepad
true, // back as touchpad click enabled (manual DS4 only)
true, // client gamepads with motion events are emulated as DS4
Expand Down Expand Up @@ -938,6 +938,17 @@
return ret;
}

std::vector<std::string_view> &
get_supported_gamepad_options() {
const auto options = platf::supported_gamepads(nullptr);

Check warning on line 943 in src/config.cpp

View check run for this annotation

Codecov / codecov/patch

src/config.cpp#L942-L943

Added lines #L942 - L943 were not covered by tests
static std::vector<std::string_view> opts {};
opts.reserve(options.size());
for (auto &opt : options) {
opts.emplace_back(opt.name);
}
return opts;

Check warning on line 949 in src/config.cpp

View check run for this annotation

Codecov / codecov/patch

src/config.cpp#L949

Added line #L949 was not covered by tests
}

void
apply_config(std::unordered_map<std::string, std::string> &&vars) {
if (!fs::exists(stream.file_apps.c_str())) {
Expand Down Expand Up @@ -1086,7 +1097,7 @@
input.key_repeat_delay = std::chrono::milliseconds { to };
}

string_restricted_f(vars, "gamepad"s, input.gamepad, platf::supported_gamepads());
string_restricted_f(vars, "gamepad"s, input.gamepad, get_supported_gamepad_options());
bool_f(vars, "ds4_back_as_touchpad_click", input.ds4_back_as_touchpad_click);
bool_f(vars, "motion_as_ds4", input.motion_as_ds4);
bool_f(vars, "touchpad_as_ds4", input.touchpad_as_ds4);
Expand Down
42 changes: 27 additions & 15 deletions src/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@

void
free_gamepad(platf::input_t &platf_input, int id) {
platf::gamepad(platf_input, id, platf::gamepad_state_t {});
platf::gamepad_update(platf_input, id, platf::gamepad_state_t {});

Check warning on line 121 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L121

Added line #L121 was not covered by tests
platf::free_gamepad(platf_input, id);

free_id(gamepadMask, id);
Expand Down Expand Up @@ -711,28 +711,28 @@
if (!release) {
// Press any synthetic modifiers required for this key
if (synthetic_modifiers & MODIFIER_SHIFT) {
platf::keyboard(platf_input, VKEY_SHIFT, false, flags);
platf::keyboard_update(platf_input, VKEY_SHIFT, false, flags);

Check warning on line 714 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L714

Added line #L714 was not covered by tests
}
if (synthetic_modifiers & MODIFIER_CTRL) {
platf::keyboard(platf_input, VKEY_CONTROL, false, flags);
platf::keyboard_update(platf_input, VKEY_CONTROL, false, flags);

Check warning on line 717 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L717

Added line #L717 was not covered by tests
}
if (synthetic_modifiers & MODIFIER_ALT) {
platf::keyboard(platf_input, VKEY_MENU, false, flags);
platf::keyboard_update(platf_input, VKEY_MENU, false, flags);

Check warning on line 720 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L720

Added line #L720 was not covered by tests
}
}

platf::keyboard(platf_input, map_keycode(key_code), release, flags);
platf::keyboard_update(platf_input, map_keycode(key_code), release, flags);

Check warning on line 724 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L724

Added line #L724 was not covered by tests

if (!release) {
// Raise any synthetic modifier keys we pressed
if (synthetic_modifiers & MODIFIER_SHIFT) {
platf::keyboard(platf_input, VKEY_SHIFT, true, flags);
platf::keyboard_update(platf_input, VKEY_SHIFT, true, flags);

Check warning on line 729 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L729

Added line #L729 was not covered by tests
}
if (synthetic_modifiers & MODIFIER_CTRL) {
platf::keyboard(platf_input, VKEY_CONTROL, true, flags);
platf::keyboard_update(platf_input, VKEY_CONTROL, true, flags);

Check warning on line 732 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L732

Added line #L732 was not covered by tests
}
if (synthetic_modifiers & MODIFIER_ALT) {
platf::keyboard(platf_input, VKEY_MENU, true, flags);
platf::keyboard_update(platf_input, VKEY_MENU, true, flags);

Check warning on line 735 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L735

Added line #L735 was not covered by tests
}
}
}
Expand Down Expand Up @@ -963,7 +963,7 @@
contact_area.second,
};

platf::touch(input->client_context.get(), abs_port, touch);
platf::touch_update(input->client_context.get(), abs_port, touch);

Check warning on line 966 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L966

Added line #L966 was not covered by tests
}

/**
Expand Down Expand Up @@ -1022,7 +1022,7 @@
contact_area.second,
};

platf::pen(input->client_context.get(), abs_port, pen);
platf::pen_update(input->client_context.get(), abs_port, pen);

Check warning on line 1025 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1025

Added line #L1025 was not covered by tests
}

/**
Expand Down Expand Up @@ -1211,18 +1211,18 @@
// Force the back button up
gamepad.back_button_state = button_state_e::UP;
state.buttonFlags &= ~platf::BACK;
platf::gamepad(platf_input, gamepad.id, state);
platf::gamepad_update(platf_input, gamepad.id, state);

Check warning on line 1214 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1214

Added line #L1214 was not covered by tests

// Press Home button
state.buttonFlags |= platf::HOME;
platf::gamepad(platf_input, gamepad.id, state);
platf::gamepad_update(platf_input, gamepad.id, state);

Check warning on line 1218 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1218

Added line #L1218 was not covered by tests

// Sleep for a short time to allow the input to be detected
std::this_thread::sleep_for(std::chrono::milliseconds(100));

// Release Home button
state.buttonFlags &= ~platf::HOME;
platf::gamepad(platf_input, gamepad.id, state);
platf::gamepad_update(platf_input, gamepad.id, state);

Check warning on line 1225 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1225

Added line #L1225 was not covered by tests

gamepad.back_timeout_id = nullptr;
};
Expand All @@ -1236,7 +1236,7 @@
}
}

platf::gamepad(platf_input, gamepad.id, gamepad_state);
platf::gamepad_update(platf_input, gamepad.id, gamepad_state);

Check warning on line 1239 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1239

Added line #L1239 was not covered by tests

gamepad.gamepad_state = gamepad_state;
}
Expand Down Expand Up @@ -1665,7 +1665,7 @@
// already released
continue;
}
platf::keyboard(platf_input, vk_from_kpid(kp.first) & 0x00FF, true, flags_from_kpid(kp.first));
platf::keyboard_update(platf_input, vk_from_kpid(kp.first) & 0x00FF, true, flags_from_kpid(kp.first));

Check warning on line 1668 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1668

Added line #L1668 was not covered by tests
key_press[kp.first] = false;
}
});
Expand All @@ -1685,6 +1685,18 @@
return std::make_unique<deinit_t>();
}

bool
probe_gamepads() {
auto input = static_cast<platf::input_t *>(platf_input.get());
const auto gamepads = platf::supported_gamepads(input);

Check warning on line 1691 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1689-L1691

Added lines #L1689 - L1691 were not covered by tests
for (auto &gamepad : gamepads) {
if (gamepad.is_enabled && gamepad.name != "auto") {
return false;

Check warning on line 1694 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1694

Added line #L1694 was not covered by tests
}
}
return true;

Check warning on line 1697 in src/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/input.cpp#L1697

Added line #L1697 was not covered by tests
}

std::shared_ptr<input_t>
alloc(safe::mail_t mail) {
auto input = std::make_shared<input_t>(
Expand Down
3 changes: 3 additions & 0 deletions src/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ namespace input {
[[nodiscard]] std::unique_ptr<platf::deinit_t>
init();

bool
probe_gamepads();

std::shared_ptr<input_t>
alloc(safe::mail_t mail);

Expand Down
5 changes: 5 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ main(int argc, char *argv[]) {

reed_solomon_init();
auto input_deinit_guard = input::init();

if (input::probe_gamepads()) {
ReenigneArcher marked this conversation as resolved.
Show resolved Hide resolved
BOOST_LOG(warning) << "No gamepad input is available"sv;
}

if (video::probe_encoders()) {
BOOST_LOG(error) << "Video failed to find working encoder"sv;
}
Expand Down
22 changes: 16 additions & 6 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ namespace platf {
constexpr std::uint32_t TOUCHPAD_BUTTON = 0x100000;
constexpr std::uint32_t MISC_BUTTON = 0x200000;

struct supported_gamepad_t {
std::string name;
bool is_enabled;
std::string reason_disabled;
};

enum class gamepad_feedback_e {
rumble,
rumble_triggers,
Expand Down Expand Up @@ -695,9 +701,9 @@ namespace platf {
void
hscroll(input_t &input, int distance);
void
keyboard(input_t &input, uint16_t modcode, bool release, uint8_t flags);
keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags);
void
gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state);
gamepad_update(input_t &input, int nr, const gamepad_state_t &gamepad_state);
void
unicode(input_t &input, char *utf8, int size);

Expand All @@ -718,7 +724,7 @@ namespace platf {
* @param touch The touch event.
*/
void
touch(client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch);
touch_update(client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch);

/**
* @brief Sends a pen event to the OS.
Expand All @@ -727,7 +733,7 @@ namespace platf {
* @param pen The pen event.
*/
void
pen(client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen);
pen_update(client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen);

/**
* @brief Sends a gamepad touch event to the OS.
Expand Down Expand Up @@ -784,6 +790,10 @@ namespace platf {
[[nodiscard]] std::unique_ptr<deinit_t>
init();

std::vector<std::string_view> &
supported_gamepads();
/**
* @brief Gets the supported gamepads for this platform backend.
* @return Vector of gamepad options and status.
*/
std::vector<supported_gamepad_t> &
supported_gamepads(input_t *input);
} // namespace platf
Loading
Loading