Convert rumble_queue into a generic feedback_queue for gamepad messages
This commit is contained in:
@@ -72,17 +72,75 @@ namespace platf {
|
||||
constexpr std::uint32_t TOUCHPAD_BUTTON = 0x100000;
|
||||
constexpr std::uint32_t MISC_BUTTON = 0x200000;
|
||||
|
||||
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;
|
||||
enum class gamepad_feedback_e {
|
||||
rumble,
|
||||
rumble_triggers,
|
||||
set_motion_event_state,
|
||||
set_rgb_led,
|
||||
};
|
||||
using rumble_queue_t = safe::mail_raw_t::queue_t<rumble_t>;
|
||||
|
||||
struct gamepad_feedback_msg_t {
|
||||
static gamepad_feedback_msg_t
|
||||
make_rumble(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq) {
|
||||
gamepad_feedback_msg_t msg;
|
||||
msg.type = gamepad_feedback_e::rumble;
|
||||
msg.id = id;
|
||||
msg.data.rumble = { lowfreq, highfreq };
|
||||
return msg;
|
||||
}
|
||||
|
||||
static gamepad_feedback_msg_t
|
||||
make_rumble_triggers(std::uint16_t id, std::uint16_t left, std::uint16_t right) {
|
||||
gamepad_feedback_msg_t msg;
|
||||
msg.type = gamepad_feedback_e::rumble_triggers;
|
||||
msg.id = id;
|
||||
msg.data.rumble_triggers = { left, right };
|
||||
return msg;
|
||||
}
|
||||
|
||||
static gamepad_feedback_msg_t
|
||||
make_motion_event_state(std::uint16_t id, std::uint8_t motion_type, std::uint16_t report_rate) {
|
||||
gamepad_feedback_msg_t msg;
|
||||
msg.type = gamepad_feedback_e::set_motion_event_state;
|
||||
msg.id = id;
|
||||
msg.data.motion_event_state.motion_type = motion_type;
|
||||
msg.data.motion_event_state.report_rate = report_rate;
|
||||
return msg;
|
||||
}
|
||||
|
||||
static gamepad_feedback_msg_t
|
||||
make_rgb_led(std::uint16_t id, std::uint8_t r, std::uint8_t g, std::uint8_t b) {
|
||||
gamepad_feedback_msg_t msg;
|
||||
msg.type = gamepad_feedback_e::set_rgb_led;
|
||||
msg.id = id;
|
||||
msg.data.rgb_led = { r, g, b };
|
||||
return msg;
|
||||
}
|
||||
|
||||
gamepad_feedback_e type;
|
||||
std::uint16_t id;
|
||||
union {
|
||||
struct {
|
||||
std::uint16_t lowfreq;
|
||||
std::uint16_t highfreq;
|
||||
} rumble;
|
||||
struct {
|
||||
std::uint16_t left_trigger;
|
||||
std::uint16_t right_trigger;
|
||||
} rumble_triggers;
|
||||
struct {
|
||||
std::uint16_t report_rate;
|
||||
std::uint8_t motion_type;
|
||||
} motion_event_state;
|
||||
struct {
|
||||
std::uint8_t r;
|
||||
std::uint8_t g;
|
||||
std::uint8_t b;
|
||||
} rgb_led;
|
||||
} data;
|
||||
};
|
||||
|
||||
using feedback_queue_t = safe::mail_raw_t::queue_t<gamepad_feedback_msg_t>;
|
||||
|
||||
namespace speaker {
|
||||
enum speaker_e {
|
||||
@@ -525,11 +583,11 @@ namespace platf {
|
||||
* @param input The input context.
|
||||
* @param nr The assigned controller number.
|
||||
* @param metadata Controller metadata from client (empty if none provided).
|
||||
* @param rumble_queue The queue for posting rumble messages to the client.
|
||||
* @param feedback_queue The queue for posting messages back to the client.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, rumble_queue_t rumble_queue);
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue);
|
||||
void
|
||||
free_gamepad(input_t &input, int nr);
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace platf {
|
||||
}
|
||||
});
|
||||
|
||||
using mail_evdev_t = std::tuple<int, uinput_t::pointer, rumble_queue_t, pollfd_t>;
|
||||
using mail_evdev_t = std::tuple<int, uinput_t::pointer, feedback_queue_t, pollfd_t>;
|
||||
|
||||
struct keycode_t {
|
||||
std::uint32_t keycode;
|
||||
@@ -452,7 +452,7 @@ namespace platf {
|
||||
public:
|
||||
KITTY_DEFAULT_CONSTR_MOVE(effect_t)
|
||||
|
||||
effect_t(int gamepadnr, uinput_t::pointer dev, rumble_queue_t &&q):
|
||||
effect_t(int gamepadnr, uinput_t::pointer dev, feedback_queue_t &&q):
|
||||
gamepadnr { gamepadnr }, dev { dev }, rumble_queue { std::move(q) }, gain { 0xFFFF }, id_to_data {} {}
|
||||
|
||||
class data_t {
|
||||
@@ -634,7 +634,7 @@ namespace platf {
|
||||
// Used as ID for adding/removinf devices from evdev notifications
|
||||
uinput_t::pointer dev;
|
||||
|
||||
rumble_queue_t rumble_queue;
|
||||
feedback_queue_t rumble_queue;
|
||||
|
||||
int gain;
|
||||
|
||||
@@ -774,11 +774,11 @@ namespace platf {
|
||||
* @brief Creates a new virtual gamepad.
|
||||
* @param nr The assigned controller number.
|
||||
* @param metadata Controller metadata from client (empty if none provided).
|
||||
* @param rumble_queue The queue for posting rumble messages to the client.
|
||||
* @param feedback_queue The queue for posting messages back to the client.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int
|
||||
alloc_gamepad(int nr, const gamepad_arrival_t &metadata, rumble_queue_t &&rumble_queue) {
|
||||
alloc_gamepad(int nr, const gamepad_arrival_t &metadata, feedback_queue_t &&feedback_queue) {
|
||||
TUPLE_2D_REF(input, gamepad_state, gamepads[nr]);
|
||||
|
||||
int err = libevdev_uinput_create_from_device(gamepad_dev.get(), LIBEVDEV_UINPUT_OPEN_MANAGED, &input);
|
||||
@@ -803,7 +803,7 @@ namespace platf {
|
||||
rumble_ctx->rumble_queue_queue.raise(
|
||||
nr,
|
||||
input.get(),
|
||||
std::move(rumble_queue),
|
||||
std::move(feedback_queue),
|
||||
pollfd_t {
|
||||
dup(libevdev_uinput_get_fd(input.get())),
|
||||
(std::int16_t) POLLIN,
|
||||
@@ -1048,9 +1048,9 @@ namespace platf {
|
||||
TUPLE_2D(weak, strong, effect.rumble(now));
|
||||
|
||||
if (old_weak != weak || old_strong != strong) {
|
||||
BOOST_LOG(debug) << "Sending haptic feedback: lowfreq [0x"sv << util::hex(weak).to_string_view() << "]: highfreq [0x"sv << util::hex(strong).to_string_view() << ']';
|
||||
BOOST_LOG(debug) << "Sending haptic feedback: lowfreq [0x"sv << util::hex(strong).to_string_view() << "]: highfreq [0x"sv << util::hex(weak).to_string_view() << ']';
|
||||
|
||||
effect.rumble_queue->raise(effect.gamepadnr, weak, strong);
|
||||
effect.rumble_queue->raise(gamepad_feedback_msg_t::make_rumble(effect.gamepadnr, strong, weak));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1492,12 +1492,12 @@ namespace platf {
|
||||
* @param input The input context.
|
||||
* @param nr The assigned controller number.
|
||||
* @param metadata Controller metadata from client (empty if none provided).
|
||||
* @param rumble_queue The queue for posting rumble messages to the client.
|
||||
* @param feedback_queue The queue for posting messages back to the client.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, rumble_queue_t rumble_queue) {
|
||||
return ((input_raw_t *) input.get())->alloc_gamepad(nr, metadata, std::move(rumble_queue));
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue) {
|
||||
return ((input_raw_t *) input.get())->alloc_gamepad(nr, metadata, std::move(feedback_queue));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -293,11 +293,11 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param input The input context.
|
||||
* @param nr The assigned controller number.
|
||||
* @param metadata Controller metadata from client (empty if none provided).
|
||||
* @param rumble_queue The queue for posting rumble messages to the client.
|
||||
* @param feedback_queue The queue for posting messages back to the client.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, rumble_queue_t rumble_queue) {
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue) {
|
||||
BOOST_LOG(info) << "alloc_gamepad: Gamepad not yet implemented for MacOS."sv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -44,12 +44,15 @@ namespace platf {
|
||||
|
||||
struct gamepad_context_t {
|
||||
target_t gp;
|
||||
rumble_queue_t rumble_queue;
|
||||
feedback_queue_t feedback_queue;
|
||||
|
||||
union {
|
||||
XUSB_REPORT x360;
|
||||
DS4_REPORT_EX ds4;
|
||||
} report;
|
||||
|
||||
gamepad_feedback_msg_t last_rumble;
|
||||
gamepad_feedback_msg_t last_rgb_led;
|
||||
};
|
||||
|
||||
constexpr float EARTH_G = 9.80665f;
|
||||
@@ -181,12 +184,12 @@ namespace platf {
|
||||
/**
|
||||
* @brief Attaches a new gamepad.
|
||||
* @param nr The gamepad index.
|
||||
* @param rumble_queue The queue to publish rumble packets.
|
||||
* @param feedback_queue The queue for posting messages back to the client.
|
||||
* @param gp_type The type of gamepad.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int
|
||||
alloc_gamepad_internal(int nr, rumble_queue_t &rumble_queue, VIGEM_TARGET_TYPE gp_type) {
|
||||
alloc_gamepad_internal(int nr, feedback_queue_t &feedback_queue, VIGEM_TARGET_TYPE gp_type) {
|
||||
auto &gamepad = gamepads[nr];
|
||||
assert(!gamepad.gp);
|
||||
|
||||
@@ -212,7 +215,7 @@ namespace platf {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gamepad.rumble_queue = std::move(rumble_queue);
|
||||
gamepad.feedback_queue = std::move(feedback_queue);
|
||||
|
||||
if (gp_type == Xbox360Wired) {
|
||||
status = vigem_target_x360_register_notification(client.get(), gamepad.gp.get(), x360_notify, this);
|
||||
@@ -247,19 +250,52 @@ namespace platf {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pass rumble data back to the host.
|
||||
* @brief Pass rumble data back to the client.
|
||||
* @param target The gamepad.
|
||||
* @param smallMotor The small motor.
|
||||
* @param largeMotor The large motor.
|
||||
* @param smallMotor The small motor.
|
||||
*/
|
||||
void
|
||||
rumble(target_t::pointer target, std::uint8_t smallMotor, std::uint8_t largeMotor) {
|
||||
rumble(target_t::pointer target, std::uint8_t largeMotor, std::uint8_t smallMotor) {
|
||||
for (int x = 0; x < gamepads.size(); ++x) {
|
||||
auto &gamepad = gamepads[x];
|
||||
|
||||
if (gamepad.gp.get() == target) {
|
||||
gamepad.rumble_queue->raise(x, ((std::uint16_t) smallMotor) << 8, ((std::uint16_t) largeMotor) << 8);
|
||||
// Convert from 8-bit to 16-bit values
|
||||
uint16_t normalizedLargeMotor = largeMotor << 8;
|
||||
uint16_t normalizedSmallMotor = smallMotor << 8;
|
||||
|
||||
// Don't resend duplicate rumble data
|
||||
if (normalizedSmallMotor != gamepad.last_rumble.data.rumble.highfreq ||
|
||||
normalizedLargeMotor != gamepad.last_rumble.data.rumble.lowfreq) {
|
||||
gamepad_feedback_msg_t msg = gamepad_feedback_msg_t::make_rumble(x, normalizedLargeMotor, normalizedSmallMotor);
|
||||
gamepad.feedback_queue->raise(msg);
|
||||
gamepad.last_rumble = msg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pass RGB LED data back to the client.
|
||||
* @param target The gamepad.
|
||||
* @param r The red channel.
|
||||
* @param g The red channel.
|
||||
* @param b The red channel.
|
||||
*/
|
||||
void
|
||||
set_rgb_led(target_t::pointer target, std::uint8_t r, std::uint8_t g, std::uint8_t b) {
|
||||
for (int x = 0; x < gamepads.size(); ++x) {
|
||||
auto &gamepad = gamepads[x];
|
||||
|
||||
if (gamepad.gp.get() == target) {
|
||||
// Don't resend duplicate RGB data
|
||||
if (r != gamepad.last_rgb_led.data.rgb_led.r || g != gamepad.last_rgb_led.data.rgb_led.g || b != gamepad.last_rgb_led.data.rgb_led.b) {
|
||||
gamepad_feedback_msg_t msg = gamepad_feedback_msg_t::make_rgb_led(x, r, g, b);
|
||||
gamepad.feedback_queue->raise(msg);
|
||||
gamepad.last_rgb_led = msg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -299,7 +335,7 @@ namespace platf {
|
||||
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
||||
<< "smallMotor: "sv << (int) smallMotor;
|
||||
|
||||
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, smallMotor, largeMotor);
|
||||
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, largeMotor, smallMotor);
|
||||
}
|
||||
|
||||
void CALLBACK
|
||||
@@ -307,13 +343,17 @@ namespace platf {
|
||||
client_t::pointer client,
|
||||
target_t::pointer target,
|
||||
std::uint8_t largeMotor, std::uint8_t smallMotor,
|
||||
DS4_LIGHTBAR_COLOR /* led_color */,
|
||||
DS4_LIGHTBAR_COLOR led_color,
|
||||
void *userdata) {
|
||||
BOOST_LOG(debug)
|
||||
<< "largeMotor: "sv << (int) largeMotor << std::endl
|
||||
<< "smallMotor: "sv << (int) smallMotor;
|
||||
<< "smallMotor: "sv << (int) smallMotor << std::endl
|
||||
<< "LED: "sv << util::hex(led_color.Red).to_string_view() << ' '
|
||||
<< util::hex(led_color.Green).to_string_view() << ' '
|
||||
<< util::hex(led_color.Blue).to_string_view() << std::endl;
|
||||
|
||||
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, smallMotor, largeMotor);
|
||||
task_pool.push(&vigem_t::rumble, (vigem_t *) userdata, target, largeMotor, smallMotor);
|
||||
task_pool.push(&vigem_t::set_rgb_led, (vigem_t *) userdata, target, led_color.Red, led_color.Green, led_color.Blue);
|
||||
}
|
||||
|
||||
struct input_raw_t {
|
||||
@@ -554,11 +594,11 @@ namespace platf {
|
||||
* @param input The input context.
|
||||
* @param nr The assigned controller number.
|
||||
* @param metadata Controller metadata from client (empty if none provided).
|
||||
* @param rumble_queue The queue for posting rumble messages to the client.
|
||||
* @param feedback_queue The queue for posting messages back to the client.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, rumble_queue_t rumble_queue) {
|
||||
alloc_gamepad(input_t &input, int nr, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue) {
|
||||
auto raw = (input_raw_t *) input.get();
|
||||
|
||||
if (!raw->vigem) {
|
||||
@@ -596,7 +636,7 @@ namespace platf {
|
||||
selectedGamepadType = Xbox360Wired;
|
||||
}
|
||||
|
||||
return raw->vigem->alloc_gamepad_internal(nr, rumble_queue, selectedGamepadType);
|
||||
return raw->vigem->alloc_gamepad_internal(nr, feedback_queue, selectedGamepadType);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user