Skip to content

Commit

Permalink
fix: PS5 pad: additional input handlers + hotplug (fake) events
Browse files Browse the repository at this point in the history
  • Loading branch information
ABeltramo committed May 26, 2024
1 parent 42995aa commit 11f7a24
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ if (UNIX AND NOT APPLE)
FetchContent_Declare(
inputtino
GIT_REPOSITORY https://github.com/games-on-whales/inputtino.git
GIT_TAG 96d1045)
GIT_TAG cf68026)
FetchContent_MakeAvailable(inputtino)

add_subdirectory(src/platforms/linux/uinput)
Expand Down
43 changes: 39 additions & 4 deletions src/core/src/platforms/linux/uinput/joypad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@ std::vector<std::pair<std::string, std::vector<std::string>>> SwitchJoypad::get_
std::vector<std::map<std::string, std::string>> PS5Joypad::get_udev_events() const {
std::vector<std::map<std::string, std::string>> events;

for (const auto sys_entry : this->get_sys_nodes()) {
auto sys_nodes = std::filesystem::directory_iterator{sys_entry};
auto sys_nodes = this->get_sys_nodes();
for (const auto sys_entry : sys_nodes) {
auto input_nodes = std::filesystem::directory_iterator{sys_entry};

for (auto sys_node : sys_nodes) {
for (auto sys_node : input_nodes) {
if (sys_node.is_directory() && (sys_node.path().filename().string().rfind("event", 0) == 0 ||
sys_node.path().filename().string().rfind("mouse", 0) == 0 ||
sys_node.path().filename().string().rfind("js", 0) == 0)) {
auto sys_path = sys_node.path().string();
sys_path.erase(0, 4); // Remove leading /sys/ from syspath TODO: what if it's not /sys/?
Expand All @@ -98,6 +100,7 @@ std::vector<std::map<std::string, std::string>> PS5Joypad::get_udev_events() con
if (name.find("Touchpad") != std::string::npos) { // touchpad
event["ID_INPUT_TOUCHPAD"] = "1";
event[".INPUT_CLASS"] = "mouse";
event["ID_INPUT_TOUCHPAD_INTEGRATION"] = "internal";
} else if (name.find("Motion") != std::string::npos) { // gyro + acc
event["ID_INPUT_ACCELEROMETER"] = "1";
event["ID_INPUT_WIDTH_MM"] = "8";
Expand All @@ -116,6 +119,28 @@ std::vector<std::map<std::string, std::string>> PS5Joypad::get_udev_events() con
}
}

// LEDS
if (sys_nodes.size() >= 1) {
auto base_path = std::filesystem::path(sys_nodes[0]).parent_path().parent_path() / "leds";
auto leds = std::filesystem::directory_iterator{base_path};
for (auto led : leds) {
if (led.is_directory()) {
auto now = std::chrono::system_clock::now();
auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();

events.emplace_back(std::map<std::string, std::string>{
{"ACTION", "add"},
{"SUBSYSTEM", "leds"},
{"DEVPATH", led.path().string()}, // TODO: should we mount this? How does the container access the led?
{"SEQNUM", "3712"},
{"USEC_INITIALIZED", std::to_string(timestamp)},
{"TAGS", ":seat:"},
{"CURRENT_TAGS", ":seat:"},
});
}
}
}

return events;
}

Expand All @@ -127,7 +152,8 @@ std::vector<std::pair<std::string, std::vector<std::string>>> PS5Joypad::get_ude

for (auto sys_node : sys_nodes) {
if (sys_node.is_directory() && (sys_node.path().filename().string().rfind("event", 0) == 0 ||
sys_node.path().filename().string().rfind("js", 0) == 0)) {
sys_node.path().filename().string().rfind("js", 0) == 0 ||
sys_node.path().filename().string().rfind("mouse", 0) == 0)) {
auto sys_path = sys_node.path().string();
sys_path.erase(0, 4); // Remove leading /sys/ from syspath TODO: what if it's not /sys/?
auto dev_path = ("/dev/input/" / sys_node.path().filename()).string();
Expand Down Expand Up @@ -173,6 +199,15 @@ std::vector<std::pair<std::string, std::vector<std::string>>> PS5Joypad::get_ude
}
}

// TODO: LEDS
/**
cat /run/udev/data/+leds:input61:rgb:indicator
I:1968647189
G:seat
Q:seat
V:1
*/

return result;
}

Expand Down
28 changes: 28 additions & 0 deletions src/moonlight-server/control/input_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ std::shared_ptr<state::JoypadTypes> create_new_joypad(const state::StreamSession
encrypt_and_send(plaintext, aes_key, *clients, session_id);
});

auto on_led_fn = ([clients = &connected_clients,
controller_number,
session_id = session.session_id,
aes_key = session.aes_key](int r, int g, int b) {
logs::log(logs::debug, "({}) LED: {}, {}, {}", controller_number, r, g, b);
auto led_pkt = ControlRGBLedPacket{
.header{.type = RGB_LED_EVENT, .length = sizeof(ControlRGBLedPacket) - sizeof(ControlPacket)},
.controller_number = boost::endian::native_to_little((uint16_t)controller_number),
.r = static_cast<uint8_t>(r),
.g = static_cast<uint8_t>(g),
.b = static_cast<uint8_t>(b)};
std::string plaintext = {(char *)&led_pkt, sizeof(led_pkt)};
encrypt_and_send(plaintext, aes_key, *clients, session_id);
});

std::shared_ptr<state::JoypadTypes> new_pad;
switch (type) {
case UNKNOWN:
Expand Down Expand Up @@ -59,7 +74,20 @@ std::shared_ptr<state::JoypadTypes> create_new_joypad(const state::StreamSession
return {};
} else {
(*result).set_on_rumble(on_rumble_fn);
(*result).set_on_led(on_led_fn);
new_pad = std::make_shared<state::JoypadTypes>(std::move(*result));

std::visit(
[&session](auto &pad) {
if (auto wl = *session.wayland_display->load()) {
for (const auto node : pad.get_udev_events()) {
if (node.find("ID_INPUT_TOUCHPAD") != node.end()) {
add_input_device(*wl, node.at("DEVNAME"));
}
}
}
},
*new_pad);
}
break;
}
Expand Down
7 changes: 6 additions & 1 deletion src/moonlight-server/runners/docker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,12 @@ void RunDocker::run(std::size_t session_id,
for (auto udev_ev : ev->udev_events) {
udev_ev["ACTION"] = "remove";
std::string udev_msg = base64_encode(map_to_string(udev_ev));
auto cmd = fmt::format("fake-udev -m {} && rm {}", udev_msg, udev_ev["DEVNAME"]);
std::string cmd;
if (udev_ev.count("DEVNAME") == 0) {
cmd = fmt::format("fake-udev -m {}", udev_msg);
} else {
cmd = fmt::format("fake-udev -m {} && rm {}", udev_msg, udev_ev["DEVNAME"]);
}
logs::log(logs::debug, "[DOCKER] Executing command: {}", cmd);
docker_api.exec(container_id, {"/bin/bash", "-c", cmd}, "root");
}
Expand Down

0 comments on commit 11f7a24

Please sign in to comment.