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

Mouse fixes #121

Merged
merged 4 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
feat: moved controller override in a per-user setting
  • Loading branch information
ABeltramo committed Oct 15, 2024
commit a1b8b7e6445fac55db491fa2b2e058bfd3d04c85
1 change: 0 additions & 1 deletion src/moonlight-server/api/endpoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ void UnixSocketServer::endpoint_AddApp(const HTTPRequest &req, std::shared_ptr<U
.opus_gst_pipeline = app.opus_gst_pipeline,
.start_virtual_compositor = app.start_virtual_compositor,
.runner = runner,
.joypad_type = state::get_controller_type(app.joypad_type),
});
});
auto res = GenericSuccessResponse{.success = true};
Expand Down
40 changes: 30 additions & 10 deletions src/moonlight-server/control/input_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ using namespace moonlight::control;
std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSession &session,
const immer::atom<enet_clients_map> &connected_clients,
int controller_number,
CONTROLLER_TYPE type,
CONTROLLER_TYPE requested_type,
uint8_t capabilities) {

auto on_rumble_fn = ([clients = &connected_clients,
Expand Down Expand Up @@ -49,11 +49,28 @@ std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSessi
});

std::shared_ptr<events::JoypadTypes> new_pad;
CONTROLLER_TYPE final_type = session.app->joypad_type == AUTO ? type : session.app->joypad_type;
auto controllers_override = session.client_settings->controllers_override;
auto final_type = controllers_override.size() > controller_number ? controllers_override[controller_number]
: wolf::config::ControllerType::AUTO;
if (final_type == wolf::config::ControllerType::AUTO) {
switch (requested_type) {
case XBOX:
final_type = wolf::config::ControllerType::XBOX;
break;
case PS:
final_type = wolf::config::ControllerType::PS;
break;
case NINTENDO:
final_type = wolf::config::ControllerType::NINTENDO;
break;
default:
final_type = wolf::config::ControllerType::AUTO;
break;
}
}
switch (final_type) {
case UNKNOWN:
case AUTO:
case XBOX: {
case wolf::config::ControllerType::AUTO:
case wolf::config::ControllerType::XBOX: {
logs::log(logs::info, "Creating Xbox joypad for controller {}", controller_number);
auto result =
XboxOneJoypad::create({.name = "Wolf X-Box One (virtual) pad",
Expand All @@ -70,7 +87,7 @@ std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSessi
}
break;
}
case PS: {
case wolf::config::ControllerType::PS: {
logs::log(logs::info, "Creating PS joypad for controller {}", controller_number);
auto result = PS5Joypad::create(
{.name = "Wolf DualSense (virtual) pad", .vendor_id = 0x054C, .product_id = 0x0CE6, .version = 0x8111});
Expand Down Expand Up @@ -99,7 +116,7 @@ std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSessi
}
break;
}
case NINTENDO:
case wolf::config::ControllerType::NINTENDO:
logs::log(logs::info, "Creating Nintendo joypad for controller {}", controller_number);
auto result = SwitchJoypad::create({.name = "Wolf Nintendo (virtual) pad",
// https://github.com/torvalds/linux/blob/master/drivers/hid/hid-ids.h#L981
Expand All @@ -116,7 +133,7 @@ std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSessi
break;
}

if (capabilities & ACCELEROMETER && final_type == PS) {
if (capabilities & ACCELEROMETER && final_type == wolf::config::ControllerType::PS) {
// Request acceleromenter events from the client at 100 Hz
logs::log(logs::info, "Requesting accelerometer events for controller {}", controller_number);
auto accelerometer_pkt = ControlMotionEventPacket{
Expand All @@ -128,7 +145,7 @@ std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSessi
encrypt_and_send(plaintext, session.aes_key, connected_clients, session.session_id);
}

if (capabilities & GYRO && final_type == PS) {
if (capabilities & GYRO && final_type == wolf::config::ControllerType::PS) {
// Request gyroscope events from the client at 100 Hz
logs::log(logs::info, "Requesting gyroscope events for controller {}", controller_number);
auto gyro_pkt = ControlMotionEventPacket{
Expand All @@ -141,7 +158,10 @@ std::shared_ptr<events::JoypadTypes> create_new_joypad(const events::StreamSessi
}

session.joypads->update([&](events::JoypadList joypads) {
logs::log(logs::debug, "[INPUT] Sending PlugDeviceEvent for joypad {} of type: {}", controller_number, (int)type);
logs::log(logs::debug,
"[INPUT] Sending PlugDeviceEvent for joypad {} of type: {}",
controller_number,
(int)final_type);

events::PlugDeviceEvent unplug_ev{.session_id = session.session_id};
std::visit(
Expand Down
2 changes: 1 addition & 1 deletion src/moonlight-server/events/events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ struct App {
bool start_virtual_compositor;
bool start_audio_server;
std::shared_ptr<Runner> runner;
moonlight::control::pkts::CONTROLLER_TYPE joypad_type;
};

using MouseTypes = std::variant<input::Mouse, virtual_display::WaylandMouse>;
Expand Down Expand Up @@ -219,6 +218,7 @@ struct StreamSession {
int audio_channel_count;

std::shared_ptr<EventBusType> event_bus;
immer::box<wolf::config::ClientSettings> client_settings;
std::shared_ptr<App> app;
std::string app_state_folder;

Expand Down
20 changes: 1 addition & 19 deletions src/moonlight-server/events/reflectors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,9 @@ template <> struct Reflector<events::App> {
bool start_virtual_compositor;
bool start_audio_server;
rfl::TaggedUnion<"type", AppCMD, AppDocker, AppChildSession> runner;
ControllerType joypad_type;
};

static ReflType from(const events::App &v) {
ControllerType ctrl_type;
switch (v.joypad_type) {
case moonlight::control::pkts::CONTROLLER_TYPE::XBOX:
ctrl_type = ControllerType::XBOX;
break;
case moonlight::control::pkts::CONTROLLER_TYPE::PS:
ctrl_type = ControllerType::PS;
break;
case moonlight::control::pkts::CONTROLLER_TYPE::NINTENDO:
ctrl_type = ControllerType::NINTENDO;
break;
case moonlight::control::pkts::CONTROLLER_TYPE::AUTO:
case moonlight::control::pkts::UNKNOWN:
ctrl_type = ControllerType::AUTO;
break;
}
return {.title = v.base.title,
.id = v.base.id,
.support_hdr = v.base.support_hdr,
Expand All @@ -74,8 +57,7 @@ template <> struct Reflector<events::App> {
.opus_gst_pipeline = v.opus_gst_pipeline,
.start_virtual_compositor = v.start_virtual_compositor,
.start_audio_server = v.start_audio_server,
.runner = v.runner->serialize(),
.joypad_type = ctrl_type};
.runner = v.runner->serialize()};
}
};

Expand Down
3 changes: 1 addition & 2 deletions src/moonlight-server/state/configTOML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ Config load_or_default(const std::string &source,
.opus_gst_pipeline = opus_gst_pipeline,
.start_virtual_compositor = app.start_virtual_compositor.value_or(true),
.start_audio_server = app.start_audio_server.value_or(true),
.runner = get_runner(app.runner, ev_bus, running_sessions),
.joypad_type = get_controller_type(app.joypad_type.value_or(ControllerType::AUTO))}};
.runner = get_runner(app.runner, ev_bus, running_sessions)}};
}) | //
ranges::to<immer::vector<immer::box<events::App>>>(); //

Expand Down
25 changes: 15 additions & 10 deletions src/moonlight-server/state/serialised_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@

namespace wolf::config {

enum class ControllerType {
XBOX,
PS,
NINTENDO,
AUTO
};

struct ClientSettings {
uint run_uid = 1000;
uint run_gid = 1000;
/* A list of forced controller overrides, the position in the array denotes the controller number */
std::vector<ControllerType> controllers_override = {};
};

struct PairedClient {
std::string client_cert;
std::string app_state_folder;
uint run_uid = 1000;
uint run_gid = 1000;
std::optional<ClientSettings> settings = {};
};

struct GstEncoderDefault {
Expand Down Expand Up @@ -81,20 +94,12 @@ struct BaseAppAudioOverride {
std::optional<std::string> sink;
};

enum class ControllerType {
XBOX,
PS,
NINTENDO,
AUTO
};

struct BaseApp {
std::string title;
std::optional<std::string> icon_png_path;
std::optional<std::string> render_node;
std::optional<BaseAppVideoOverride> video;
std::optional<BaseAppAudioOverride> audio;
std::optional<ControllerType> joypad_type;
std::optional<bool> start_virtual_compositor;
std::optional<bool> start_audio_server;
rfl::TaggedUnion<"type", AppCMD, AppDocker, AppChildSession> runner;
Expand Down
20 changes: 11 additions & 9 deletions src/moonlight-server/state/sessions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,18 @@ inline std::shared_ptr<events::StreamSession> create_stream_session(immer::box<s
auto video_stream_port = get_next_available_port(state->running_sessions->load(), true);
auto audio_stream_port = get_next_available_port(state->running_sessions->load(), false);

auto session = events::StreamSession{.display_mode = display_mode,
.audio_channel_count = audio_channel_count,
.event_bus = state->event_bus,
.app = std::make_shared<events::App>(run_app),
.app_state_folder = full_path.string(),
auto session = events::StreamSession{
.display_mode = display_mode,
.audio_channel_count = audio_channel_count,
.event_bus = state->event_bus,
.client_settings = current_client.settings.value_or(wolf::config::ClientSettings{}),
.app = std::make_shared<events::App>(run_app),
.app_state_folder = full_path.string(),

// client info
.session_id = state::get_client_id(current_client),
.video_stream_port = video_stream_port,
.audio_stream_port = audio_stream_port};
// client info
.session_id = state::get_client_id(current_client),
.video_stream_port = video_stream_port,
.audio_stream_port = audio_stream_port};

return std::make_shared<events::StreamSession>(session);
}
Expand Down
4 changes: 3 additions & 1 deletion tests/assets/config.test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ config_version = 4
# A list of paired clients that will be allowed to stream
[[paired_clients]]
client_cert = "A VERY VALID CERTIFICATE"
app_state_folder = "some/folder"
[paired_clients.settings]
run_uid = 1234
run_gid = 5678
app_state_folder = "some/folder"
controllers_override = ["PS"]


[[apps]]
Expand Down
4 changes: 2 additions & 2 deletions tests/platforms/linux/inputtino.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ TEST_CASE("uinput - mouse", "[UINPUT]") {

TEST_CASE("uinput - joypad", "[UINPUT]") {
SECTION("OLD Moonlight: create joypad on first packet arrival") {
events::App app = {.joypad_type = moonlight::control::pkts::CONTROLLER_TYPE::AUTO};
events::App app = {};
auto session =
events::StreamSession{.event_bus = std::make_shared<events::EventBusType>(), .app = std::make_shared<events::App>(app)};
short controller_number = 1;
Expand All @@ -306,7 +306,7 @@ TEST_CASE("uinput - joypad", "[UINPUT]") {
}

SECTION("NEW Moonlight: create joypad with CONTROLLER_ARRIVAL") {
events::App app = {.joypad_type = moonlight::control::pkts::CONTROLLER_TYPE::AUTO};
events::App app = {};
auto session =
events::StreamSession{.event_bus = std::make_shared<events::EventBusType>(), .app = std::make_shared<events::App>(app)};
uint8_t controller_number = 1;
Expand Down
2 changes: 1 addition & 1 deletion tests/platforms/linux/uhid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using namespace moonlight::control;
using namespace std::string_literals;

TEST_CASE("Create PS5 pad with CONTROLLER_ARRIVAL", "[UHID]") {
events::App app = {.joypad_type = moonlight::control::pkts::CONTROLLER_TYPE::AUTO};
events::App app = {};
auto session =
events::StreamSession{.event_bus = std::make_shared<events::EventBusType>(), .app = std::make_shared<events::App>(app)};
uint8_t controller_number = 1;
Expand Down
7 changes: 3 additions & 4 deletions tests/testMoonlight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ TEST_CASE("LocalState load TOML", "[LocalState]") {
REQUIRE_THAT(first_app->h264_gst_pipeline, Equals("video_source !\ndefault !\nh264_pipeline !\nvideo_sink"));
REQUIRE_THAT(first_app->hevc_gst_pipeline, Equals("video_source !\ndefault !\nhevc_pipeline !\nvideo_sink"));
REQUIRE_THAT(first_app->av1_gst_pipeline, Equals("video_source !\nparams !\nav1_pipeline !\nvideo_sink"));
REQUIRE(first_app->joypad_type == moonlight::control::pkts::CONTROLLER_TYPE::AUTO);
REQUIRE(first_app->start_virtual_compositor);
REQUIRE(first_app->render_node == "/dev/dri/renderD128");
auto first_app_runner = rfl::get<AppDocker>(first_app->runner->serialize().variant());
Expand All @@ -54,7 +53,6 @@ TEST_CASE("LocalState load TOML", "[LocalState]") {
REQUIRE_THAT(second_app->av1_gst_pipeline,
Equals("override DEFAULT SOURCE !\nparams !\nav1_pipeline !\nvideo_sink"));
REQUIRE(!second_app->start_virtual_compositor);
REQUIRE(second_app->joypad_type == moonlight::control::pkts::CONTROLLER_TYPE::XBOX);
REQUIRE(second_app->render_node == "/tmp/dead_beef");
auto second_app_runner = rfl::get<AppCMD>(second_app->runner->serialize().variant());
REQUIRE_THAT(second_app_runner.run_cmd, Equals("destroy_computer_now"));
Expand All @@ -63,8 +61,9 @@ TEST_CASE("LocalState load TOML", "[LocalState]") {
SECTION("Paired Clients") {
REQUIRE_THAT(state.paired_clients->load().get(), Catch::Matchers::SizeIs(1));
REQUIRE_THAT(state.paired_clients->load().get()[0]->client_cert, Equals("A VERY VALID CERTIFICATE"));
REQUIRE(state.paired_clients->load().get()[0]->run_uid == 1234);
REQUIRE(state.paired_clients->load().get()[0]->run_gid == 5678);
REQUIRE(state.paired_clients->load().get()[0]->settings.value().run_uid == 1234);
REQUIRE(state.paired_clients->load().get()[0]->settings.value().run_gid == 5678);
REQUIRE(state.paired_clients->load().get()[0]->settings.value().controllers_override[0] == wolf::config::ControllerType::PS);
REQUIRE_THAT(state.paired_clients->load().get()[0]->app_state_folder, Equals("some/folder"));
}
}
Expand Down