Support Rumble on Windows
This commit is contained in:
+18
-12
@@ -46,7 +46,7 @@ void free_id(std::bitset<N> &gamepad_mask, int id) {
|
|||||||
gamepad_mask[id] = false;
|
gamepad_mask[id] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static util::TaskPool::task_id_t task_id {};
|
static util::TaskPool::task_id_t key_press_repeat_id {};
|
||||||
static std::unordered_map<short, bool> key_press {};
|
static std::unordered_map<short, bool> key_press {};
|
||||||
static std::array<std::uint8_t, 5> mouse_press {};
|
static std::array<std::uint8_t, 5> mouse_press {};
|
||||||
|
|
||||||
@@ -84,10 +84,13 @@ struct gamepad_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct input_t {
|
struct input_t {
|
||||||
input_t(safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event)
|
input_t(
|
||||||
|
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event,
|
||||||
|
platf::rumble_queue_t rumble_queue)
|
||||||
: active_gamepad_state {},
|
: active_gamepad_state {},
|
||||||
gamepads(MAX_GAMEPADS),
|
gamepads(MAX_GAMEPADS),
|
||||||
touch_port_event { std::move(touch_port_event) },
|
touch_port_event { std::move(touch_port_event) },
|
||||||
|
rumble_queue { std::move(rumble_queue) },
|
||||||
mouse_left_button_timeout {},
|
mouse_left_button_timeout {},
|
||||||
touch_port { 0, 0, 0, 0, 0, 0, 1.0f } {}
|
touch_port { 0, 0, 0, 0, 0, 0, 1.0f } {}
|
||||||
|
|
||||||
@@ -95,6 +98,7 @@ struct input_t {
|
|||||||
std::vector<gamepad_t> gamepads;
|
std::vector<gamepad_t> gamepads;
|
||||||
|
|
||||||
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event;
|
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event;
|
||||||
|
platf::rumble_queue_t rumble_queue;
|
||||||
|
|
||||||
util::ThreadPool::task_id_t mouse_left_button_timeout;
|
util::ThreadPool::task_id_t mouse_left_button_timeout;
|
||||||
|
|
||||||
@@ -314,13 +318,13 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet
|
|||||||
void repeat_key(short key_code) {
|
void repeat_key(short key_code) {
|
||||||
// If key no longer pressed, stop repeating
|
// If key no longer pressed, stop repeating
|
||||||
if(!key_press[key_code]) {
|
if(!key_press[key_code]) {
|
||||||
task_id = nullptr;
|
key_press_repeat_id = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
platf::keyboard(platf_input, key_code & 0x00FF, false);
|
platf::keyboard(platf_input, key_code & 0x00FF, false);
|
||||||
|
|
||||||
task_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id;
|
key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
short map_keycode(short keycode) {
|
short map_keycode(short keycode) {
|
||||||
@@ -345,12 +349,12 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
|
|||||||
auto &pressed = key_press[packet->keyCode];
|
auto &pressed = key_press[packet->keyCode];
|
||||||
if(!pressed) {
|
if(!pressed) {
|
||||||
if(!release) {
|
if(!release) {
|
||||||
if(task_id) {
|
if(key_press_repeat_id) {
|
||||||
task_pool.cancel(task_id);
|
task_pool.cancel(key_press_repeat_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config::input.key_repeat_delay.count() > 0) {
|
if(config::input.key_repeat_delay.count() > 0) {
|
||||||
task_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_delay, packet->keyCode).task_id;
|
key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_delay, packet->keyCode).task_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -374,7 +378,7 @@ void passthrough(PNV_SCROLL_PACKET packet) {
|
|||||||
platf::scroll(platf_input, util::endian::big(packet->scrollAmt1));
|
platf::scroll(platf_input, util::endian::big(packet->scrollAmt1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std::int16_t new_state) {
|
int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std::int16_t new_state, platf::rumble_queue_t rumble_queue) {
|
||||||
auto xorGamepadMask = old_state ^ new_state;
|
auto xorGamepadMask = old_state ^ new_state;
|
||||||
if(!xorGamepadMask) {
|
if(!xorGamepadMask) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -400,7 +404,7 @@ int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(platf::alloc_gamepad(platf_input, id)) {
|
if(platf::alloc_gamepad(platf_input, id, std::move(rumble_queue))) {
|
||||||
free_id(gamepadMask, id);
|
free_id(gamepadMask, id);
|
||||||
// allocating a gamepad failed: solution: ignore gamepads
|
// allocating a gamepad failed: solution: ignore gamepads
|
||||||
// The implementations of platf::alloc_gamepad already has logging
|
// The implementations of platf::alloc_gamepad already has logging
|
||||||
@@ -416,7 +420,7 @@ int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std
|
|||||||
}
|
}
|
||||||
|
|
||||||
void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
|
void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
|
||||||
if(updateGamepads(input->gamepads, input->active_gamepad_state, packet->activeGamepadMask)) {
|
if(updateGamepads(input->gamepads, input->active_gamepad_state, packet->activeGamepadMask, input->rumble_queue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,7 +556,7 @@ void passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&in
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reset(std::shared_ptr<input_t> &input) {
|
void reset(std::shared_ptr<input_t> &input) {
|
||||||
task_pool.cancel(task_id);
|
task_pool.cancel(key_press_repeat_id);
|
||||||
task_pool.cancel(input->mouse_left_button_timeout);
|
task_pool.cancel(input->mouse_left_button_timeout);
|
||||||
|
|
||||||
// Ensure input is synchronous, by using the task_pool
|
// Ensure input is synchronous, by using the task_pool
|
||||||
@@ -576,7 +580,9 @@ void init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<input_t> alloc(safe::mail_t mail) {
|
std::shared_ptr<input_t> alloc(safe::mail_t mail) {
|
||||||
auto input = std::make_shared<input_t>(mail->event<input::touch_port_t>(mail::touch_port));
|
auto input = std::make_shared<input_t>(
|
||||||
|
mail->event<input::touch_port_t>(mail::touch_port),
|
||||||
|
mail->queue<platf::rumble_t>(mail::rumble));
|
||||||
|
|
||||||
// Workaround to ensure new frames will be captured when a client connects
|
// Workaround to ensure new frames will be captured when a client connects
|
||||||
task_pool.pushDelayed([]() {
|
task_pool.pushDelayed([]() {
|
||||||
|
|||||||
+2
-1
@@ -5,11 +5,12 @@
|
|||||||
#ifndef SUNSHINE_INPUT_H
|
#ifndef SUNSHINE_INPUT_H
|
||||||
#define SUNSHINE_INPUT_H
|
#define SUNSHINE_INPUT_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "platform/common.h"
|
#include "platform/common.h"
|
||||||
#include "thread_safe.h"
|
#include "thread_safe.h"
|
||||||
|
|
||||||
namespace input {
|
namespace input {
|
||||||
|
|
||||||
struct input_t;
|
struct input_t;
|
||||||
|
|
||||||
void print(void *input);
|
void print(void *input);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ MAIL(audio_packets);
|
|||||||
// Local mail
|
// Local mail
|
||||||
MAIL(touch_port);
|
MAIL(touch_port);
|
||||||
MAIL(idr);
|
MAIL(idr);
|
||||||
|
MAIL(rumble);
|
||||||
#undef MAIL
|
#undef MAIL
|
||||||
} // namespace mail
|
} // namespace mail
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "sunshine/thread_safe.h"
|
||||||
#include "sunshine/utility.h"
|
#include "sunshine/utility.h"
|
||||||
|
|
||||||
struct sockaddr;
|
struct sockaddr;
|
||||||
@@ -34,6 +36,18 @@ constexpr std::uint16_t B = 0x2000;
|
|||||||
constexpr std::uint16_t X = 0x4000;
|
constexpr std::uint16_t X = 0x4000;
|
||||||
constexpr std::uint16_t Y = 0x8000;
|
constexpr std::uint16_t Y = 0x8000;
|
||||||
|
|
||||||
|
struct rumble_t {
|
||||||
|
KITTY_DEFAULT_CONSTR(rumble_t)
|
||||||
|
|
||||||
|
rumble_t(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq)
|
||||||
|
: id { id }, lowfreq { lowfreq }, highfreq { highfreq } {}
|
||||||
|
|
||||||
|
std::uint16_t id;
|
||||||
|
std::uint16_t lowfreq;
|
||||||
|
std::uint16_t highfreq;
|
||||||
|
};
|
||||||
|
using rumble_queue_t = safe::mail_raw_t::queue_t<rumble_t>;
|
||||||
|
|
||||||
namespace speaker {
|
namespace speaker {
|
||||||
enum speaker_e {
|
enum speaker_e {
|
||||||
FRONT_LEFT,
|
FRONT_LEFT,
|
||||||
@@ -243,7 +257,7 @@ void scroll(input_t &input, int distance);
|
|||||||
void keyboard(input_t &input, uint16_t modcode, bool release);
|
void keyboard(input_t &input, uint16_t modcode, bool release);
|
||||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state);
|
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state);
|
||||||
|
|
||||||
int alloc_gamepad(input_t &input, int nr);
|
int alloc_gamepad(input_t &input, int nr, rumble_queue_t &&rumble_queue);
|
||||||
void free_gamepad(input_t &input, int nr);
|
void free_gamepad(input_t &input, int nr);
|
||||||
|
|
||||||
#define SERVICE_NAME "Sunshine"
|
#define SERVICE_NAME "Sunshine"
|
||||||
|
|||||||
@@ -18,11 +18,18 @@ constexpr touch_port_t target_touch_port {
|
|||||||
65535, 65535
|
65535, 65535
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
||||||
|
using target_t = util::safe_ptr<_VIGEM_TARGET_T, vigem_target_free>;
|
||||||
|
|
||||||
|
void CALLBACK x360_notify(
|
||||||
|
client_t::pointer client,
|
||||||
|
target_t::pointer target,
|
||||||
|
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||||
|
std::uint8_t /* led_number */,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
class vigem_t {
|
class vigem_t {
|
||||||
public:
|
public:
|
||||||
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
|
||||||
using target_t = util::safe_ptr<_VIGEM_TARGET_T, vigem_target_free>;
|
|
||||||
|
|
||||||
int init() {
|
int init() {
|
||||||
VIGEM_ERROR status;
|
VIGEM_ERROR status;
|
||||||
|
|
||||||
@@ -40,8 +47,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_x360(int nr) {
|
int alloc_x360(int nr, rumble_queue_t &rumble_queue) {
|
||||||
auto &x360 = x360s[nr];
|
auto &[rumble, x360] = x360s[nr];
|
||||||
assert(!x360);
|
assert(!x360);
|
||||||
|
|
||||||
x360.reset(vigem_target_x360_alloc());
|
x360.reset(vigem_target_x360_alloc());
|
||||||
@@ -52,11 +59,18 @@ public:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rumble = std::move(rumble_queue);
|
||||||
|
|
||||||
|
status = vigem_target_x360_register_notification(client.get(), x360.get(), x360_notify, this);
|
||||||
|
if(!VIGEM_SUCCESS(status)) {
|
||||||
|
BOOST_LOG(warning) << "Couldn't register notifications for rumble support ["sv << util::hex(status).to_string_view() << ']';
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_target(int nr) {
|
void free_target(int nr) {
|
||||||
auto &x360 = x360s[nr];
|
auto &[_, x360] = x360s[nr];
|
||||||
|
|
||||||
if(x360 && vigem_target_is_attached(x360.get())) {
|
if(x360 && vigem_target_is_attached(x360.get())) {
|
||||||
auto status = vigem_target_remove(client.get(), x360.get());
|
auto status = vigem_target_remove(client.get(), x360.get());
|
||||||
@@ -68,9 +82,21 @@ public:
|
|||||||
x360.reset();
|
x360.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rumble(target_t::pointer target, std::uint8_t largeMotor, std::uint8_t smallMotor) {
|
||||||
|
for(int x = 0; x < x360s.size(); ++x) {
|
||||||
|
auto &[rumble_queue, x360] = x360s[x];
|
||||||
|
|
||||||
|
if(x360.get() == target) {
|
||||||
|
rumble_queue->raise(x, largeMotor, smallMotor);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~vigem_t() {
|
~vigem_t() {
|
||||||
if(client) {
|
if(client) {
|
||||||
for(auto &x360 : x360s) {
|
for(auto &[_, x360] : x360s) {
|
||||||
if(x360 && vigem_target_is_attached(x360.get())) {
|
if(x360 && vigem_target_is_attached(x360.get())) {
|
||||||
auto status = vigem_target_remove(client.get(), x360.get());
|
auto status = vigem_target_remove(client.get(), x360.get());
|
||||||
if(!VIGEM_SUCCESS(status)) {
|
if(!VIGEM_SUCCESS(status)) {
|
||||||
@@ -83,10 +109,25 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<target_t> x360s;
|
std::vector<std::pair<rumble_queue_t, target_t>> x360s;
|
||||||
|
|
||||||
client_t client;
|
client_t client;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void CALLBACK x360_notify(
|
||||||
|
client_t::pointer client,
|
||||||
|
target_t::pointer target,
|
||||||
|
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||||
|
std::uint8_t /* led_number */,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
BOOST_LOG(debug)
|
||||||
|
<< "largeMotor: "sv << (int)largeMotor << std::endl
|
||||||
|
<< "smallMotor: "sv << (int)smallMotor;
|
||||||
|
|
||||||
|
task_pool.push(&vigem_t::rumble, (vigem_t *)userdata, target, largeMotor, smallMotor);
|
||||||
|
}
|
||||||
|
|
||||||
input_t input() {
|
input_t input() {
|
||||||
input_t result { new vigem_t {} };
|
input_t result { new vigem_t {} };
|
||||||
|
|
||||||
@@ -110,6 +151,7 @@ retry:
|
|||||||
BOOST_LOG(error) << "Couldn't send input"sv;
|
BOOST_LOG(error) << "Couldn't send input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) {
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
|
|
||||||
@@ -242,12 +284,12 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
send_input(i);
|
send_input(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int alloc_gamepad(input_t &input, int nr) {
|
int alloc_gamepad(input_t &input, int nr, rumble_queue_t &&rumble_queue) {
|
||||||
if(!input) {
|
if(!input) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((vigem_t *)input.get())->alloc_x360(nr);
|
return ((vigem_t *)input.get())->alloc_x360(nr, rumble_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_gamepad(input_t &input, int nr) {
|
void free_gamepad(input_t &input, int nr) {
|
||||||
@@ -257,6 +299,7 @@ void free_gamepad(input_t &input, int nr) {
|
|||||||
|
|
||||||
((vigem_t *)input.get())->free_target(nr);
|
((vigem_t *)input.get())->free_target(nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||||
// If there is no gamepad support
|
// If there is no gamepad support
|
||||||
if(!input) {
|
if(!input) {
|
||||||
@@ -266,7 +309,7 @@ void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
|||||||
auto vigem = (vigem_t *)input.get();
|
auto vigem = (vigem_t *)input.get();
|
||||||
|
|
||||||
auto &xusb = *(PXUSB_REPORT)&gamepad_state;
|
auto &xusb = *(PXUSB_REPORT)&gamepad_state;
|
||||||
auto &x360 = vigem->x360s[nr];
|
auto &[_, x360] = vigem->x360s[nr];
|
||||||
|
|
||||||
auto status = vigem_target_x360_update(vigem->client.get(), x360.get(), xusb);
|
auto status = vigem_target_x360_update(vigem->client.get(), x360.get(), xusb);
|
||||||
if(!VIGEM_SUCCESS(status)) {
|
if(!VIGEM_SUCCESS(status)) {
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ struct ctx_t {
|
|||||||
|
|
||||||
class proc_t {
|
class proc_t {
|
||||||
public:
|
public:
|
||||||
KITTY_DEFAULT_CONSTR_THROW(proc_t)
|
KITTY_DEFAULT_CONSTR_MOVE_THROW(proc_t)
|
||||||
|
|
||||||
proc_t(
|
proc_t(
|
||||||
boost::process::environment &&env,
|
boost::process::environment &&env,
|
||||||
|
|||||||
+58
-6
@@ -101,6 +101,16 @@ struct control_terminate_t {
|
|||||||
std::uint32_t ec;
|
std::uint32_t ec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct control_rumble_t {
|
||||||
|
control_header_v2 header;
|
||||||
|
|
||||||
|
std::uint32_t useless;
|
||||||
|
|
||||||
|
std::uint16_t id;
|
||||||
|
std::uint16_t lowfreq;
|
||||||
|
std::uint16_t highfreq;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct control_encrypted_t {
|
typedef struct control_encrypted_t {
|
||||||
std::uint16_t encryptedHeaderType; // Always LE 0x0001
|
std::uint16_t encryptedHeaderType; // Always LE 0x0001
|
||||||
std::uint16_t length; // sizeof(seq) + 16 byte tag + secondary header and data
|
std::uint16_t length; // sizeof(seq) + 16 byte tag + secondary header and data
|
||||||
@@ -281,6 +291,8 @@ struct session_t {
|
|||||||
|
|
||||||
net::peer_t peer;
|
net::peer_t peer;
|
||||||
std::uint8_t seq;
|
std::uint8_t seq;
|
||||||
|
|
||||||
|
platf::rumble_queue_t rumble_queue;
|
||||||
} control;
|
} control;
|
||||||
|
|
||||||
safe::mail_raw_t::event_t<bool> shutdown_event;
|
safe::mail_raw_t::event_t<bool> shutdown_event;
|
||||||
@@ -318,9 +330,13 @@ static inline std::string_view encode_control(session_t *session, const std::str
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint16_t packet_length = bytes + crypto::cipher::tag_size + sizeof(control_encrypted_t::seq);
|
||||||
|
|
||||||
|
packet->encryptedHeaderType = util::endian::little(0x0001);
|
||||||
|
packet->length = util::endian::little(packet_length);
|
||||||
packet->seq = util::endian::little(seq);
|
packet->seq = util::endian::little(seq);
|
||||||
|
|
||||||
return std::string_view { (char *)tagged_cipher.data(), (std::size_t)bytes };
|
return std::string_view { (char *)tagged_cipher.data(), packet_length + sizeof(control_encrypted_t) - sizeof(control_encrypted_t::seq) };
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_broadcast(broadcast_ctx_t &ctx);
|
int start_broadcast(broadcast_ctx_t &ctx);
|
||||||
@@ -537,6 +553,38 @@ std::vector<uint8_t> replace(const std::string_view &original, const std::string
|
|||||||
return replaced;
|
return replaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int send_rumble(session_t *session, std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq) {
|
||||||
|
if(!session->control.peer) {
|
||||||
|
BOOST_LOG(warning) << "Couldn't send rumble data, still waiting for PING from Moonlight"sv;
|
||||||
|
// Still waiting for PING from Moonlight
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
control_rumble_t plaintext;
|
||||||
|
plaintext.header.type = packetTypes[IDX_RUMBLE_DATA];
|
||||||
|
plaintext.header.payloadLength = sizeof(control_rumble_t) - sizeof(control_header_v2);
|
||||||
|
|
||||||
|
plaintext.useless = 0xC0FFEE;
|
||||||
|
plaintext.id = util::endian::little(id);
|
||||||
|
plaintext.lowfreq = util::endian::little(lowfreq << 8);
|
||||||
|
plaintext.highfreq = util::endian::little(highfreq << 8);
|
||||||
|
|
||||||
|
BOOST_LOG(fatal) << util::hex(plaintext.id).to_string_view() << " :: "sv << util::hex(plaintext.lowfreq).to_string_view() << " :: "sv << util::hex(plaintext.highfreq).to_string_view();
|
||||||
|
std::array<std::uint8_t,
|
||||||
|
sizeof(control_encrypted_t) + crypto::cipher::round_to_pkcs7_padded(sizeof(plaintext)) + crypto::cipher::tag_size>
|
||||||
|
encrypted_payload;
|
||||||
|
|
||||||
|
auto payload = encode_control(session, util::view(plaintext), encrypted_payload);
|
||||||
|
if(session->broadcast_ref->control_server.send(payload, session->control.peer)) {
|
||||||
|
TUPLE_2D(port, addr, platf::from_sockaddr_ex((sockaddr *)&session->control.peer->address.address));
|
||||||
|
BOOST_LOG(warning) << "Couldn't send termination code to ["sv << addr << ':' << port << ']';
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void controlBroadcastThread(control_server_t *server) {
|
void controlBroadcastThread(control_server_t *server) {
|
||||||
server->map(packetTypes[IDX_PERIODIC_PING], [](session_t *session, const std::string_view &payload) {
|
server->map(packetTypes[IDX_PERIODIC_PING], [](session_t *session, const std::string_view &payload) {
|
||||||
BOOST_LOG(verbose) << "type [IDX_START_A]"sv;
|
BOOST_LOG(verbose) << "type [IDX_START_A]"sv;
|
||||||
@@ -696,6 +744,13 @@ void controlBroadcastThread(control_server_t *server) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &rumble_queue = session->control.rumble_queue;
|
||||||
|
while(rumble_queue->peek()) {
|
||||||
|
auto rumble = rumble_queue->pop();
|
||||||
|
|
||||||
|
send_rumble(session, rumble->id, rumble->lowfreq, rumble->highfreq);
|
||||||
|
}
|
||||||
|
|
||||||
++pos;
|
++pos;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -706,7 +761,7 @@ void controlBroadcastThread(control_server_t *server) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->iterate(500ms);
|
server->iterate(50ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let all remaining connections know the server is shutting down
|
// Let all remaining connections know the server is shutting down
|
||||||
@@ -722,10 +777,6 @@ void controlBroadcastThread(control_server_t *server) {
|
|||||||
sizeof(control_encrypted_t) + crypto::cipher::round_to_pkcs7_padded(sizeof(plaintext)) + crypto::cipher::tag_size>
|
sizeof(control_encrypted_t) + crypto::cipher::round_to_pkcs7_padded(sizeof(plaintext)) + crypto::cipher::tag_size>
|
||||||
encrypted_payload;
|
encrypted_payload;
|
||||||
|
|
||||||
auto packet = (control_encrypted_p)encrypted_payload.data();
|
|
||||||
packet->encryptedHeaderType = util::endian::little(0x0001);
|
|
||||||
packet->length = encrypted_payload.size() - sizeof(control_encrypted_t) + 4;
|
|
||||||
|
|
||||||
auto lg = server->_map_addr_session.lock();
|
auto lg = server->_map_addr_session.lock();
|
||||||
for(auto pos = std::begin(*server->_map_addr_session); pos != std::end(*server->_map_addr_session); ++pos) {
|
for(auto pos = std::begin(*server->_map_addr_session); pos != std::end(*server->_map_addr_session); ++pos) {
|
||||||
auto session = pos->second.second;
|
auto session = pos->second.second;
|
||||||
@@ -1353,6 +1404,7 @@ std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypt
|
|||||||
|
|
||||||
session->config = config;
|
session->config = config;
|
||||||
|
|
||||||
|
session->control.rumble_queue = mail->queue<platf::rumble_t>(mail::rumble);
|
||||||
session->control.iv = iv;
|
session->control.iv = iv;
|
||||||
session->control.cipher = crypto::cipher::gcm_t {
|
session->control.cipher = crypto::cipher::gcm_t {
|
||||||
gcm_key, false
|
gcm_key, false
|
||||||
|
|||||||
+7
-2
@@ -56,16 +56,21 @@ struct argument_type<T(U)> { typedef U type; };
|
|||||||
x &operator=(x &&) noexcept = default; \
|
x &operator=(x &&) noexcept = default; \
|
||||||
x();
|
x();
|
||||||
|
|
||||||
#define KITTY_DEFAULT_CONSTR(x) \
|
#define KITTY_DEFAULT_CONSTR_MOVE(x) \
|
||||||
x(x &&) noexcept = default; \
|
x(x &&) noexcept = default; \
|
||||||
x &operator=(x &&) noexcept = default; \
|
x &operator=(x &&) noexcept = default; \
|
||||||
x() = default;
|
x() = default;
|
||||||
|
|
||||||
#define KITTY_DEFAULT_CONSTR_THROW(x) \
|
#define KITTY_DEFAULT_CONSTR_MOVE_THROW(x) \
|
||||||
x(x &&) = default; \
|
x(x &&) = default; \
|
||||||
x &operator=(x &&) = default; \
|
x &operator=(x &&) = default; \
|
||||||
x() = default;
|
x() = default;
|
||||||
|
|
||||||
|
#define KITTY_DEFAULT_CONSTR(x) \
|
||||||
|
KITTY_DEFAULT_CONSTR_MOVE(x) \
|
||||||
|
x(const x &) noexcept = default; \
|
||||||
|
x &operator=(const x &) = default;
|
||||||
|
|
||||||
#define TUPLE_2D(a, b, expr) \
|
#define TUPLE_2D(a, b, expr) \
|
||||||
decltype(expr) a##_##b = expr; \
|
decltype(expr) a##_##b = expr; \
|
||||||
auto &a = std::get<0>(a##_##b); \
|
auto &a = std::get<0>(a##_##b); \
|
||||||
|
|||||||
+1
-1
@@ -276,7 +276,7 @@ struct encoder_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct option_t {
|
struct option_t {
|
||||||
KITTY_DEFAULT_CONSTR(option_t)
|
KITTY_DEFAULT_CONSTR_MOVE(option_t)
|
||||||
option_t(const option_t &) = default;
|
option_t(const option_t &) = default;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ struct packet_raw_t : public AVPacket {
|
|||||||
std::string_view old;
|
std::string_view old;
|
||||||
std::string_view _new;
|
std::string_view _new;
|
||||||
|
|
||||||
KITTY_DEFAULT_CONSTR(replace_t)
|
KITTY_DEFAULT_CONSTR_MOVE(replace_t)
|
||||||
|
|
||||||
replace_t(std::string_view old, std::string_view _new) noexcept : old { std::move(old) }, _new { std::move(_new) } {}
|
replace_t(std::string_view old, std::string_view _new) noexcept : old { std::move(old) }, _new { std::move(_new) } {}
|
||||||
};
|
};
|
||||||
|
|||||||
Vendored
+1
-1
Submodule third-party/ViGEmClient updated: 52682b59c4...f719a1d9eb
Reference in New Issue
Block a user