mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-03-25 13:43:33 +00:00
Dynamically plug and unplug emulated gamepads
This commit is contained in:
parent
3a6c18279e
commit
b10c971374
@ -125,9 +125,28 @@ void passthrough(platf::input_t &input, PNV_SCROLL_PACKET packet) {
|
||||
}
|
||||
|
||||
void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
|
||||
if(packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) {
|
||||
BOOST_LOG(warning) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']';
|
||||
auto xorGamepadMask = input->active_gamepad_state ^ packet->activeGamepadMask;
|
||||
|
||||
for(int x = 0; x < platf::MAX_GAMEPADS; ++x) {
|
||||
if((xorGamepadMask >> x) & 1) {
|
||||
if((input->active_gamepad_state >> x) & 1) {
|
||||
platf::gamepad(input->input, x, platf::gamepad_state_t {});
|
||||
platf::free_gamepad(input->input, x);
|
||||
}
|
||||
else if(platf::alloc_gamepad(input->input, x)) {
|
||||
//TODO: abort stream session
|
||||
}
|
||||
}
|
||||
}
|
||||
input->active_gamepad_state = packet->activeGamepadMask;
|
||||
|
||||
if(packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) {
|
||||
BOOST_LOG(error) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!((input->active_gamepad_state >> packet->controllerNumber) & 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -135,9 +154,7 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET pa
|
||||
|
||||
display_cursor = false;
|
||||
|
||||
std::uint16_t bf;
|
||||
std::memcpy(&bf, &packet->buttonFlags, sizeof(std::uint16_t));
|
||||
|
||||
std::uint16_t bf = packet->buttonFlags;
|
||||
platf::gamepad_state_t gamepad_state{
|
||||
bf,
|
||||
packet->leftTrigger,
|
||||
@ -254,15 +271,7 @@ void reset_helper(std::shared_ptr<input_t> input) {
|
||||
}
|
||||
}
|
||||
|
||||
NV_MULTI_CONTROLLER_PACKET fake_packet;
|
||||
fake_packet.buttonFlags = 0;
|
||||
fake_packet.leftStickX = 0;
|
||||
fake_packet.leftStickY = 0;
|
||||
fake_packet.rightStickX = 0;
|
||||
fake_packet.rightStickY = 0;
|
||||
fake_packet.leftTrigger = 0;
|
||||
fake_packet.rightTrigger = 0;
|
||||
|
||||
NV_MULTI_CONTROLLER_PACKET fake_packet {};
|
||||
passthrough(input, &fake_packet);
|
||||
}
|
||||
|
||||
@ -274,6 +283,6 @@ void reset(std::shared_ptr<input_t> &input) {
|
||||
task_pool.push(reset_helper, input);
|
||||
}
|
||||
|
||||
input_t::input_t() : mouse_press {}, input { platf::input() }, gamepads(platf::MAX_GAMEPADS) {}
|
||||
input_t::input_t() : mouse_press {}, input { platf::input() }, active_gamepad_state {}, gamepads (platf::MAX_GAMEPADS) {}
|
||||
gamepad_t::gamepad_t() : gamepad_state {}, back_timeout_id {}, back_button_state { button_state_e::NONE } {}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ struct input_t {
|
||||
|
||||
platf::input_t input;
|
||||
|
||||
std::uint16_t active_gamepad_state;
|
||||
std::vector<gamepad_t> gamepads;
|
||||
};
|
||||
|
||||
|
@ -82,7 +82,7 @@ using input_t = util::safe_ptr<void, freeInput>;
|
||||
std::string get_mac_address(const std::string_view &address);
|
||||
|
||||
std::unique_ptr<mic_t> microphone(std::uint32_t sample_rate);
|
||||
std::shared_ptr<display_t> display();
|
||||
std::unique_ptr<display_t> display();
|
||||
|
||||
input_t input();
|
||||
void move_mouse(input_t &input, int deltaX, int deltaY);
|
||||
@ -90,6 +90,9 @@ void button_mouse(input_t &input, int button, bool release);
|
||||
void scroll(input_t &input, int distance);
|
||||
void keyboard(input_t &input, uint16_t modcode, bool release);
|
||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state);
|
||||
|
||||
int alloc_gamepad(input_t &input, int nr);
|
||||
void free_gamepad(input_t &input, int nr);
|
||||
}
|
||||
|
||||
#endif //SUNSHINE_COMMON_H
|
||||
|
@ -326,7 +326,7 @@ std::unique_ptr<display_t> shm_display() {
|
||||
return shm;
|
||||
}
|
||||
|
||||
std::shared_ptr<display_t> display() {
|
||||
std::unique_ptr<display_t> display() {
|
||||
auto shm_disp = shm_display();
|
||||
|
||||
if(!shm_disp) {
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
std::filesystem::remove(gamepad_path);
|
||||
}
|
||||
|
||||
gamepads[nr].first.reset();
|
||||
gamepads[nr] = std::make_pair(uinput_t{}, gamepad_state_t {});
|
||||
}
|
||||
|
||||
int create_mouse() {
|
||||
@ -69,7 +69,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_gamepad(int nr) {
|
||||
int alloc_gamepad(int nr) {
|
||||
TUPLE_2D_REF(input, gamepad_state, gamepads[nr]);
|
||||
|
||||
libevdev_uinput *buf;
|
||||
@ -86,8 +86,12 @@ public:
|
||||
std::stringstream ss;
|
||||
ss << "sunshine_gamepad_"sv << nr;
|
||||
std::filesystem::path gamepad_path { ss.str() };
|
||||
std::filesystem::create_symlink(libevdev_uinput_get_devnode(input.get()), gamepad_path);
|
||||
|
||||
if(std::filesystem::is_symlink(gamepad_path)) {
|
||||
std::filesystem::remove(gamepad_path);
|
||||
}
|
||||
|
||||
std::filesystem::create_symlink(libevdev_uinput_get_devnode(input.get()), gamepad_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -293,6 +297,14 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
||||
XFlush(keyboard.get());
|
||||
}
|
||||
|
||||
int alloc_gamepad(input_t &input, int nr) {
|
||||
return ((input_raw_t*)input.get())->alloc_gamepad(nr);
|
||||
}
|
||||
|
||||
void free_gamepad(input_t &input, int nr) {
|
||||
((input_raw_t*)input.get())->clear_gamepad(nr);
|
||||
}
|
||||
|
||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||
TUPLE_2D_REF(uinput, gamepad_state_old, ((input_raw_t*)input.get())->gamepads[nr]);
|
||||
|
||||
@ -461,7 +473,6 @@ input_t input() {
|
||||
input_t result { new input_raw_t() };
|
||||
auto &gp = *(input_raw_t*)result.get();
|
||||
|
||||
gp.gamepads.resize(MAX_GAMEPADS);
|
||||
gp.keyboard.reset(XOpenDisplay(nullptr));
|
||||
|
||||
// If we do not have a keyboard, gamepad or mouse, no input is possible and we should abort
|
||||
@ -471,18 +482,13 @@ input_t input() {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
gp.gamepads.resize(MAX_GAMEPADS);
|
||||
|
||||
// Ensure starting from clean slate
|
||||
gp.clear();
|
||||
gp.mouse_dev = mouse();
|
||||
gp.gamepad_dev = x360();
|
||||
|
||||
for(int x = 0; x < gp.gamepads.size(); ++x) {
|
||||
if(gp.create_gamepad(x)) {
|
||||
log_flush();
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(gp.create_mouse()) {
|
||||
log_flush();
|
||||
std::abort();
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <Ws2tcpip.h>
|
||||
#include <Winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <winuser.h>
|
||||
#include <iphlpapi.h>
|
||||
@ -36,20 +36,38 @@ public:
|
||||
}
|
||||
|
||||
x360s.resize(MAX_GAMEPADS);
|
||||
for(auto &x360 : x360s) {
|
||||
x360.reset(vigem_target_x360_alloc());
|
||||
|
||||
status = vigem_target_add(client.get(), x360.get());
|
||||
if(!VIGEM_SUCCESS(status)) {
|
||||
BOOST_LOG(error) << "Couldn't add Gamepad to ViGEm connection ["sv << util::hex(status).to_string_view() << ']';
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
int alloc_x360(int nr) {
|
||||
auto &x360 = x360s[nr];
|
||||
assert(!x360);
|
||||
|
||||
x360.reset(vigem_target_x360_alloc());
|
||||
auto status = vigem_target_add(client.get(), x360.get());
|
||||
if(!VIGEM_SUCCESS(status)) {
|
||||
BOOST_LOG(error) << "Couldn't add Gamepad to ViGEm connection ["sv << util::hex(status).to_string_view() << ']';
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_target(int nr) {
|
||||
auto &x360 = x360s[nr];
|
||||
|
||||
if(x360 && vigem_target_is_attached(x360.get())) {
|
||||
auto status = vigem_target_remove(client.get(), x360.get());
|
||||
if(!VIGEM_SUCCESS(status)) {
|
||||
BOOST_LOG(warning) << "Couldn't detach gamepad from ViGEm ["sv << util::hex(status).to_string_view() << ']';
|
||||
}
|
||||
}
|
||||
|
||||
x360.reset();
|
||||
}
|
||||
|
||||
~vigem_t() {
|
||||
if(client) {
|
||||
for(auto &x360 : x360s) {
|
||||
@ -263,6 +281,21 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
||||
}
|
||||
}
|
||||
|
||||
int alloc_gamepad(input_t &input, int nr) {
|
||||
if(!input) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((vigem_t*)input.get())->alloc_x360(nr);
|
||||
}
|
||||
|
||||
void free_gamepad(input_t &input, int nr) {
|
||||
if(!input) {
|
||||
return;
|
||||
}
|
||||
|
||||
((vigem_t*)input.get())->free_target(nr);
|
||||
}
|
||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||
// If there is no gamepad support
|
||||
if(!input) {
|
||||
|
@ -717,7 +717,7 @@ const char *format_str[] = {
|
||||
}
|
||||
|
||||
namespace platf {
|
||||
std::shared_ptr<display_t> display() {
|
||||
std::unique_ptr<display_t> display() {
|
||||
auto disp = std::make_unique<dxgi::display_t>();
|
||||
|
||||
if (disp->init()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user