Implementing virtual mouse and mode switch

This commit is contained in:
Denis 2023-12-16 22:10:57 +01:00
parent 6072f88002
commit 0b7f888a2f
No known key found for this signature in database
GPG key ID: DD9B63F805CF5C03
8 changed files with 502 additions and 153 deletions

View file

@ -35,6 +35,7 @@ add_executable(${STRAY_EXECUTABLE_NAME}
settings.c
virt_ds4.c
virt_ds5.c
virt_mouse.c
devices_status.c
)
@ -44,6 +45,7 @@ add_executable(${ALLINONE_EXECUTABLE_NAME}
settings.c
virt_ds4.c
virt_ds5.c
virt_mouse.c
devices_status.c
dev_evdev.c
dev_iio.c

366
dev_out.c
View file

@ -5,6 +5,7 @@
#include "message.h"
#include "virt_ds4.h"
#include "virt_ds5.h"
#include "virt_mouse.h"
#include <libconfig.h>
@ -20,6 +21,24 @@ static void handle_incoming_message_gamepad_action(
}
}
static void handle_incoming_message_mouse_event(
const dev_out_settings_t *const in_settings,
const in_message_mouse_event_t *const msg_payload,
mouse_status_t *const inout_mouse
) {
if (msg_payload->type == MOUSE_ELEMENT_X) {
inout_mouse->x += msg_payload->value;
} else if (msg_payload->type == MOUSE_ELEMENT_Y) {
inout_mouse->y += msg_payload->value;
} else if (msg_payload->type == MOUSE_BTN_LEFT) {
inout_mouse->btn_left = msg_payload->value;
} else if (msg_payload->type == MOUSE_BTN_MIDDLE) {
inout_mouse->btn_middle = msg_payload->value;
} else if (msg_payload->type == MOUSE_BTN_RIGHT) {
inout_mouse->btn_right = msg_payload->value;
}
}
static void handle_incoming_message_gamepad_set(
const dev_out_settings_t *const in_settings,
const in_message_gamepad_set_element_t *const msg_payload,
@ -196,6 +215,12 @@ static void handle_incoming_message(
&msg->data.action,
&dev_stats->gamepad
);
} else if (msg->type == MOUSE_EVENT) {
handle_incoming_message_mouse_event(
in_settings,
&msg->data.mouse_event,
&dev_stats->mouse
);
}
}
@ -229,14 +254,26 @@ void *dev_out_thread_func(void *ptr) {
break;
}
int current_gamepad_fd = -1;
int current_keyboard_fd = -1;
int current_mouse_fd = -1;
union {
virt_dualshock_t ds4;
virt_dualsense_t ds5;
} controller_data;
int current_gamepad_fd = -1;
//int current_keyboard_fd = -1;
//int current_mouse_fd = -1;
virt_mouse_t mouse_data;
const int mouse_init_res = virt_mouse_init(&mouse_data);
if (mouse_init_res < 0) {
fprintf(stderr, "Unable to initialize virtual mouse -- will continue regardless\n");
} else {
current_mouse_fd = virt_mouse_get_fd(&mouse_data);
}
const int64_t kbd_report_timing_us = 1125;
const int64_t mouse_report_timing_us = 950;
const int64_t gamepad_report_timing_us = 1250;
if (current_gamepad == GAMEPAD_DUALSENSE) {
const int ds5_init_res = virt_dualsense_init(&controller_data.ds5);
@ -260,8 +297,8 @@ void *dev_out_thread_func(void *ptr) {
gettimeofday(&now, NULL);
struct timeval gamepad_last_hid_report_sent = now;
//struct timeval mouse_last_hid_report_sent = now;
//struct timeval keyboard_last_hid_report_sent = now;
struct timeval mouse_last_hid_report_sent = now;
struct timeval keyboard_last_hid_report_sent = now;
uint8_t tmp_buf[256];
@ -272,9 +309,12 @@ void *dev_out_thread_func(void *ptr) {
break;
}
const int64_t gamepad_time_diff_usecs = get_timediff_usec(&gamepad_last_hid_report_sent, &now);
const int64_t mouse_time_diff_usecs = get_timediff_usec(&mouse_last_hid_report_sent, &now);
const int64_t kbd_time_diff_usecs = get_timediff_usec(&keyboard_last_hid_report_sent, &now);
gettimeofday(&now, NULL);
int64_t gamepad_time_diff_usecs = get_timediff_usec(&gamepad_last_hid_report_sent, &now);
if (gamepad_time_diff_usecs >= 1250) {
if (gamepad_time_diff_usecs >= gamepad_report_timing_us) {
gamepad_last_hid_report_sent = now;
if (current_gamepad == GAMEPAD_DUALSENSE) {
@ -284,170 +324,200 @@ void *dev_out_thread_func(void *ptr) {
virt_dualshock_compose(&controller_data.ds4, &dev_out_data->dev_stats.gamepad, tmp_buf);
virt_dualshock_send(&controller_data.ds4, tmp_buf);
}
} else {
FD_ZERO(&read_fds);
// this does reset the for, ensuring every other device has nothing to say
continue;
} else if (mouse_time_diff_usecs >= mouse_report_timing_us) {
mouse_last_hid_report_sent = now;
virt_mouse_send(&mouse_data, &dev_out_data->dev_stats.mouse, &now);
// this does reset the for, ensuring every other device has nothing to say
continue;
} else if (kbd_time_diff_usecs >= kbd_report_timing_us) {
keyboard_last_hid_report_sent = now;
// this does reset the for, ensuring every other device has nothing to say
continue;
}
// once here no output device needs to send out its report
FD_ZERO(&read_fds);
if (dev_out_data->communication.type == ipc_unix_pipe) {
FD_SET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds);
} else if (dev_out_data->communication.type == ipc_server_sockets) {
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
if (fd > 0) {
FD_SET(fd, &read_fds);
}
}
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
}
}
if (current_mouse_fd > 0) {
FD_SET(current_mouse_fd, &read_fds);
}
// TODO: FD_SET(current_keyboard_fd, &read_fds);
if (current_gamepad_fd > 0) {
FD_SET(current_gamepad_fd, &read_fds);
}
const int64_t timeout_gamepad_time_diff_usecs = gamepad_report_timing_us - gamepad_time_diff_usecs;
const int64_t timeout_mouse_time_diff_usecs = mouse_time_diff_usecs - mouse_report_timing_us;
const int64_t timeout_kbd_time_diff_usecs = kbd_report_timing_us - kbd_time_diff_usecs;
int64_t next_timing_out_device_diff_usecs = timeout_kbd_time_diff_usecs < timeout_mouse_time_diff_usecs ? timeout_kbd_time_diff_usecs : timeout_mouse_time_diff_usecs;
next_timing_out_device_diff_usecs = next_timing_out_device_diff_usecs < timeout_gamepad_time_diff_usecs ? next_timing_out_device_diff_usecs : timeout_gamepad_time_diff_usecs;
// calculate the shortest timeout between one of the multiple device will needs to send out its hid report
struct timeval timeout = {
.tv_sec = (__time_t)next_timing_out_device_diff_usecs / (__time_t)1000000,
.tv_usec = (__suseconds_t)next_timing_out_device_diff_usecs % (__suseconds_t)1000000,
};
int ready_fds = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
gamepad_status_qam_quirk_ext_time(&dev_out_data->dev_stats.gamepad, &now);
if (ready_fds == -1) {
const int err = errno;
fprintf(stderr, "Error reading events for output devices: %d\n", err);
continue;
} else if (ready_fds == 0) {
// timeout: do nothing but continue. next iteration will take care
continue;
}
if ((current_gamepad_fd > 0) && (FD_ISSET(current_gamepad_fd, &read_fds))) {
const uint64_t prev_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
const uint64_t prev_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
out_message_t out_msgs[4];
size_t out_msgs_count = 0;
if (current_gamepad == GAMEPAD_DUALSENSE) {
virt_dualsense_event(&controller_data.ds5, &dev_out_data->dev_stats.gamepad);
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
virt_dualshock_event(&controller_data.ds4, &dev_out_data->dev_stats.gamepad);
}
const uint64_t current_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
const uint64_t current_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
if (current_leds_events_count != prev_leds_events_count) {
const out_message_t msg = {
.type = OUT_MSG_TYPE_LEDS,
.data = {
.leds = {
.r = dev_out_data->dev_stats.gamepad.leds_colors[0],
.g = dev_out_data->dev_stats.gamepad.leds_colors[1],
.b = dev_out_data->dev_stats.gamepad.leds_colors[2],
}
}
};
out_msgs[out_msgs_count++] = msg;
}
if (current_motors_events_count != prev_motors_events_count) {
const out_message_t msg = {
.type = OUT_MSG_TYPE_RUMBLE,
.data = {
.rumble = {
.motors_left = dev_out_data->dev_stats.gamepad.motors_intensity[0],
.motors_right = dev_out_data->dev_stats.gamepad.motors_intensity[1],
}
}
};
out_msgs[out_msgs_count++] = msg;
}
// send out game-generated events to sockets
if (dev_out_data->communication.type == ipc_unix_pipe) {
FD_SET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds);
for (int msg_idx = 0; msg_idx < out_msgs_count; ++msg_idx) {
const int write_res = write(dev_out_data->communication.endpoint.pipe.out_message_pipe_fd, (void*)&out_msgs[msg_idx], sizeof(out_message_t));
if (write_res != sizeof(out_message_t)) {
fprintf(stderr, "Error in writing out_message to out_message_pipe: %d\n", write_res);
}
}
} else if (dev_out_data->communication.type == ipc_server_sockets) {
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
if (fd > 0) {
FD_SET(fd, &read_fds);
}
}
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
}
}
// TODO: FD_SET(current_mouse_fd, &read_fds);
// TODO: FD_SET(current_keyboard_fd, &read_fds);
FD_SET(current_gamepad_fd, &read_fds);
// calculate the shortest timeout between one of the multiple device will needs to send out its hid report
struct timeval timeout = {
.tv_sec = (__time_t)gamepad_time_diff_usecs / (__time_t)1000000,
.tv_usec = (__suseconds_t)gamepad_time_diff_usecs % (__suseconds_t)1000000,
};
int ready_fds = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
gamepad_status_qam_quirk_ext_time(&dev_out_data->dev_stats.gamepad, &now);
if (ready_fds == -1) {
const int err = errno;
fprintf(stderr, "Error reading events for output devices: %d\n", err);
continue;
} else if (ready_fds == 0) {
// timeout: do nothing but continue. next iteration will take care
continue;
}
if (FD_ISSET(current_gamepad_fd, &read_fds)) {
const uint64_t prev_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
const uint64_t prev_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
out_message_t out_msgs[4];
size_t out_msgs_count = 0;
if (current_gamepad == GAMEPAD_DUALSENSE) {
virt_dualsense_event(&controller_data.ds5, &dev_out_data->dev_stats.gamepad);
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
virt_dualshock_event(&controller_data.ds4, &dev_out_data->dev_stats.gamepad);
}
const uint64_t current_leds_events_count = dev_out_data->dev_stats.gamepad.leds_events_count;
const uint64_t current_motors_events_count = dev_out_data->dev_stats.gamepad.rumble_events_count;
if (current_leds_events_count != prev_leds_events_count) {
const out_message_t msg = {
.type = OUT_MSG_TYPE_LEDS,
.data = {
.leds = {
.r = dev_out_data->dev_stats.gamepad.leds_colors[0],
.g = dev_out_data->dev_stats.gamepad.leds_colors[1],
.b = dev_out_data->dev_stats.gamepad.leds_colors[2],
}
}
};
out_msgs[out_msgs_count++] = msg;
}
if (current_motors_events_count != prev_motors_events_count) {
const out_message_t msg = {
.type = OUT_MSG_TYPE_RUMBLE,
.data = {
.rumble = {
.motors_left = dev_out_data->dev_stats.gamepad.motors_intensity[0],
.motors_right = dev_out_data->dev_stats.gamepad.motors_intensity[1],
}
}
};
out_msgs[out_msgs_count++] = msg;
}
// send out game-generated events to sockets
if (dev_out_data->communication.type == ipc_unix_pipe) {
for (int msg_idx = 0; msg_idx < out_msgs_count; ++msg_idx) {
const int write_res = write(dev_out_data->communication.endpoint.pipe.out_message_pipe_fd, (void*)&out_msgs[msg_idx], sizeof(out_message_t));
if (write_res != sizeof(out_message_t)) {
fprintf(stderr, "Error in writing out_message to out_message_pipe: %d\n", write_res);
}
}
} else if (dev_out_data->communication.type == ipc_server_sockets) {
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
if (dev_out_data->communication.endpoint.ssocket.clients[i] > 0) {
for (int msg_idx = 0; msg_idx < out_msgs_count; ++msg_idx) {
const int write_res = write(dev_out_data->communication.endpoint.ssocket.clients[i], (void*)&out_msgs[msg_idx], sizeof(out_message_t));
if (write_res != sizeof(out_message_t)) {
fprintf(stderr, "Error in writing out_message to socket number %d: %d\n", i, write_res);
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
}
if (dev_out_data->communication.endpoint.ssocket.clients[i] > 0) {
for (int msg_idx = 0; msg_idx < out_msgs_count; ++msg_idx) {
const int write_res = write(dev_out_data->communication.endpoint.ssocket.clients[i], (void*)&out_msgs[msg_idx], sizeof(out_message_t));
if (write_res != sizeof(out_message_t)) {
fprintf(stderr, "Error in writing out_message to socket number %d: %d\n", i, write_res);
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
}
}
}
}
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
}
}
}
// read and handle incoming data: this data is packed into in_message_t
if (dev_out_data->communication.type == ipc_unix_pipe) {
if (FD_ISSET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds)) {
in_message_t incoming_message;
const size_t in_message_pipe_read_res = read(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, (void*)&incoming_message, sizeof(in_message_t));
if (in_message_pipe_read_res == sizeof(in_message_t)) {
handle_incoming_message(
&dev_out_data->settings,
&incoming_message,
&dev_out_data->dev_stats
);
} else {
fprintf(stderr, "Error reading from in_message_pipe_fd: got %zu bytes, expected %zu bytes\n", in_message_pipe_read_res, sizeof(in_message_t));
}
}
} else if (dev_out_data->communication.type == ipc_server_sockets) {
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
if ((fd > 0) && (FD_ISSET(fd, &read_fds))) {
in_message_t incoming_message;
const size_t in_message_pipe_read_res = read(fd, (void*)&incoming_message, sizeof(in_message_t));
if (in_message_pipe_read_res == sizeof(in_message_t)) {
handle_incoming_message(
&dev_out_data->settings,
&incoming_message,
&dev_out_data->dev_stats
);
} else {
fprintf(stderr, "Error reading from socket number %d: got %zu bytes, expected %zu bytes\n", i, in_message_pipe_read_res, sizeof(in_message_t));
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
}
}
}
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
}
}
}
// read and handle incoming data: this data is packed into in_message_t
if (dev_out_data->communication.type == ipc_unix_pipe) {
if (FD_ISSET(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, &read_fds)) {
in_message_t incoming_message;
const size_t in_message_pipe_read_res = read(dev_out_data->communication.endpoint.pipe.in_message_pipe_fd, (void*)&incoming_message, sizeof(in_message_t));
if (in_message_pipe_read_res == sizeof(in_message_t)) {
handle_incoming_message(
&dev_out_data->settings,
&incoming_message,
&dev_out_data->dev_stats
);
} else {
fprintf(stderr, "Error reading from in_message_pipe_fd: got %zu bytes, expected %zu bytes\n", in_message_pipe_read_res, sizeof(in_message_t));
}
}
} else if (dev_out_data->communication.type == ipc_server_sockets) {
if (pthread_mutex_lock(&dev_out_data->communication.endpoint.ssocket.mutex) == 0) {
for (int i = 0; i < MAX_CONNECTED_CLIENTS; ++i) {
const int fd = dev_out_data->communication.endpoint.ssocket.clients[i];
if ((fd > 0) && (FD_ISSET(fd, &read_fds))) {
in_message_t incoming_message;
const size_t in_message_pipe_read_res = read(fd, (void*)&incoming_message, sizeof(in_message_t));
if (in_message_pipe_read_res == sizeof(in_message_t)) {
handle_incoming_message(
&dev_out_data->settings,
&incoming_message,
&dev_out_data->dev_stats
);
} else {
fprintf(stderr, "Error reading from socket number %d: got %zu bytes, expected %zu bytes\n", i, in_message_pipe_read_res, sizeof(in_message_t));
close(dev_out_data->communication.endpoint.ssocket.clients[i]);
dev_out_data->communication.endpoint.ssocket.clients[i] = -1;
}
}
}
pthread_mutex_unlock(&dev_out_data->communication.endpoint.ssocket.mutex);
}
}
}
// close the output device
// close the gamepad output device
if (current_gamepad == GAMEPAD_DUALSENSE) {
virt_dualsense_close(&controller_data.ds5);
} else if (current_gamepad == GAMEPAD_DUALSHOCK) {
virt_dualshock_close(&controller_data.ds4);
}
// close the mouse device
virt_mouse_close(&mouse_data);
// end communication
if (dev_out_data->communication.type == ipc_server_sockets) {
// close every client socket

View file

@ -4,6 +4,16 @@ void kbd_status_init(keyboard_status_t *const stats) {
stats->connected = true;
}
void mouse_status_init(mouse_status_t *const stats) {
stats->connected = true;
stats->x = 0;
stats->y = 0;
stats->btn_left = 0;
stats->btn_middle = 0;
stats->btn_right = 0;
}
void gamepad_status_init(gamepad_status_t *const stats) {
stats->connected = true;
stats->joystick_positions[0][0] = 0;
@ -45,7 +55,7 @@ void gamepad_status_init(gamepad_status_t *const stats) {
void devices_status_init(devices_status_t *const stats) {
gamepad_status_init(&stats->gamepad);
kbd_status_init(&stats->kbd);
// TODO: mouse init
mouse_status_init(&stats->mouse);
}
void gamepad_status_qam_quirk(gamepad_status_t *const gamepad_stats) {

View file

@ -69,6 +69,19 @@ typedef struct keyboard_status {
bool connected;
} keyboard_status_t;
typedef struct mouse_status {
bool connected;
int32_t x;
int32_t y;
uint8_t btn_left;
uint8_t btn_middle;
uint8_t btn_right;
} mouse_status_t;
typedef struct devices_status {
// this mutex MUST be grabbed when reading and/or writing below properties
pthread_mutex_t mutex;
@ -77,8 +90,12 @@ typedef struct devices_status {
keyboard_status_t kbd;
mouse_status_t mouse;
} devices_status_t;
void mouse_status_init(mouse_status_t *const stats);
void kbd_status_init(keyboard_status_t *const stats);
void gamepad_status_init(gamepad_status_t *const stats);

View file

@ -64,6 +64,19 @@ typedef struct in_message_gamepad_set_element {
} status;
} in_message_gamepad_set_element_t;
typedef enum mouse_element {
MOUSE_ELEMENT_X,
MOUSE_ELEMENT_Y,
MOUSE_BTN_LEFT,
MOUSE_BTN_MIDDLE,
MOUSE_BTN_RIGHT,
} mouse_element_t;
typedef struct in_message_mouse_event {
mouse_element_t type;
int32_t value;
} in_message_mouse_event_t;
typedef enum in_message_gamepad_action {
GAMEPAD_ACTION_PRESS_AND_RELEASE_CENTER,
GAMEPAD_ACTION_OPEN_STEAM_QAM,
@ -72,6 +85,7 @@ typedef enum in_message_gamepad_action {
typedef enum in_in_message_type {
GAMEPAD_SET_ELEMENT,
GAMEPAD_ACTION,
MOUSE_EVENT,
} in_message_type_t;
typedef struct in_message {
@ -83,6 +97,8 @@ typedef struct in_message {
in_message_gamepad_action_t action;
in_message_gamepad_set_element_t gamepad_set;
in_message_mouse_event_t mouse_event;
} data;
} in_message_t;

View file

@ -1,7 +1,9 @@
#include "rog_ally.h"
#include "input_dev.h"
#include "dev_hidraw.h"
#include "message.h"
#include "xbox360.h"
#include <linux/input-event-codes.h>
typedef enum rc71l_platform_mode {
rc71l_platform_mode_hidraw,
@ -99,10 +101,10 @@ int asus_kbd_ev_map(
.type = GAMEPAD_SET_ELEMENT,
.data = {
.gamepad_set = {
.element = GAMEPAD_BTN_L5,
.status = {
.btn = e->ev[1].value,
}
.element = GAMEPAD_BTN_L5,
.status = {
.btn = e->ev[1].value,
}
}
}
};
@ -166,6 +168,68 @@ int asus_kbd_ev_map(
printf("Asus MCU kernel interface found at %s -- switching mode\n", kernel_sysfs);
free(kernel_sysfs);
} else if (e->ev[i].code == BTN_LEFT) {
const in_message_t current_message = {
.type = MOUSE_EVENT,
.data = {
.mouse_event = {
.type = MOUSE_BTN_LEFT,
.value = e->ev[i].value,
}
}
};
messages[written_msg++] = current_message;
} else if (e->ev[i].code == BTN_MIDDLE) {
const in_message_t current_message = {
.type = MOUSE_EVENT,
.data = {
.mouse_event = {
.type = MOUSE_BTN_MIDDLE,
.value = e->ev[i].value,
}
}
};
messages[written_msg++] = current_message;
} else if (e->ev[i].code == BTN_RIGHT) {
const in_message_t current_message = {
.type = MOUSE_EVENT,
.data = {
.mouse_event = {
.type = MOUSE_BTN_RIGHT,
.value = e->ev[i].value,
}
}
};
messages[written_msg++] = current_message;
}
} else if (e->ev[i].type == EV_REL) {
if (e->ev[i].code == REL_X) {
const in_message_t current_message = {
.type = MOUSE_EVENT,
.data = {
.mouse_event = {
.type = MOUSE_ELEMENT_X,
.value = e->ev[i].value,
}
}
};
messages[written_msg++] = current_message;
} else if (e->ev[i].code == REL_Y) {
const in_message_t current_message = {
.type = MOUSE_EVENT,
.data = {
.mouse_event = {
.type = MOUSE_ELEMENT_Y,
.value = e->ev[i].value,
}
}
};
messages[written_msg++] = current_message;
}
}
}

141
virt_mouse.c Normal file
View file

@ -0,0 +1,141 @@
#include "virt_mouse.h"
#include <linux/input-event-codes.h>
#include <linux/input.h>
#include <sys/time.h>
int virt_mouse_init(virt_mouse_t *const mouse) {
int ret = -EINVAL;
mouse->status_recv = 0;
int fd = open("/dev/uinput", O_RDWR);
if(fd < 0) {
ret = errno;
goto virt_mouse_init_err;
}
ioctl(fd, UI_SET_EVBIT, EV_REL);
ioctl(fd, UI_SET_EVBIT, EV_KEY);
ioctl(fd, UI_SET_EVBIT, EV_MSC);
ioctl(fd, UI_SET_EVBIT, EV_SYN);
ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP);
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
ioctl(fd, UI_SET_RELBIT, REL_X);
ioctl(fd, UI_SET_RELBIT, REL_Y);
ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
ioctl(fd, UI_SET_RELBIT, REL_WHEEL_HI_RES);
struct uinput_setup dev = {0};
strncpy(dev.name, VIRT_MOUSE_DEV_NAME, UINPUT_MAX_NAME_SIZE-1);
dev.id.bustype = BUS_VIRTUAL;
dev.id.vendor = VIRT_MOUSE_DEV_VENDOR_ID;
dev.id.product = VIRT_MOUSE_DEV_PRODUCT_ID;
dev.id.version = VIRT_MOUSE_DEV_VERSION;
if(ioctl(fd, UI_DEV_SETUP, &dev) < 0) {
ret = errno > 0 ? errno : -1 * errno;
ret = ret == 0 ? -EIO : ret;
goto virt_mouse_init_err;
}
if(ioctl(fd, UI_DEV_CREATE) < 0) {
ret = errno > 0 ? errno : -1 * errno;
ret = ret == 0 ? -EIO : ret;
goto virt_mouse_init_err;
}
// initialization ok
mouse->prev_btn_left = 0;
mouse->prev_btn_right = 0;
mouse->prev_btn_middle = 0;
mouse->fd = fd;
ret = 0;
virt_mouse_init_err:
if (ret != 0) {
mouse->fd = -1;
close(fd);
}
return ret;
}
int virt_mouse_get_fd(virt_mouse_t *const mouse) {
return mouse->fd;
}
int virt_mouse_send(virt_mouse_t *const mouse, mouse_status_t *const status, struct timeval *const now) {
int res = 0;
struct input_event tmp_ev;
if (now == NULL) {
gettimeofday(&tmp_ev.time, NULL);
} else {
tmp_ev.time = *now;
}
tmp_ev.type = EV_REL;
if (status->x > 0) {
tmp_ev.code = REL_X;
tmp_ev.value = status->x;
if (write(mouse->fd, &tmp_ev, sizeof(tmp_ev)) != sizeof(struct input_event)) {
res = errno < 0 ? errno : -1 * errno;
goto virt_mouse_send_err;
} else {
status->x = 0;
}
}
if (status->y > 0) {
tmp_ev.code = REL_Y;
tmp_ev.value = status->y;
if (write(mouse->fd, &tmp_ev, sizeof(tmp_ev)) != sizeof(struct input_event)) {
res = errno < 0 ? errno : -1 * errno;
goto virt_mouse_send_err;
} else {
status->y = 0;
}
}
tmp_ev.type = EV_KEY;
if (status->btn_left != mouse->prev_btn_left) {
mouse->prev_btn_left = status->btn_left;
tmp_ev.code = BTN_LEFT;
tmp_ev.value = status->btn_left;
if (write(mouse->fd, &tmp_ev, sizeof(tmp_ev)) != sizeof(struct input_event)) {
res = errno < 0 ? errno : -1 * errno;
goto virt_mouse_send_err;
}
}
if (status->btn_middle != mouse->prev_btn_middle) {
mouse->prev_btn_middle = status->btn_middle;
tmp_ev.code = BTN_MIDDLE;
tmp_ev.value = status->btn_middle;
if (write(mouse->fd, &tmp_ev, sizeof(tmp_ev)) != sizeof(struct input_event)) {
res = errno < 0 ? errno : -1 * errno;
goto virt_mouse_send_err;
}
}
if (status->btn_right != mouse->prev_btn_right) {
mouse->prev_btn_right = status->btn_right;
tmp_ev.code = BTN_RIGHT;
tmp_ev.value = status->btn_right;
if (write(mouse->fd, &tmp_ev, sizeof(tmp_ev)) != sizeof(struct input_event)) {
res = errno < 0 ? errno : -1 * errno;
goto virt_mouse_send_err;
}
}
virt_mouse_send_err:
return res;
}
void virt_mouse_close(virt_mouse_t *const mouse) {
close(mouse->fd);
}

29
virt_mouse.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include "message.h"
#include "devices_status.h"
#define VIRT_MOUSE_DEV_NAME "ROGueENEMY - mouse"
#define VIRT_MOUSE_DEV_VENDOR_ID 0x108c
#define VIRT_MOUSE_DEV_PRODUCT_ID 0x0323
#define VIRT_MOUSE_DEV_VERSION 0x0111
typedef struct virt_mouse {
int fd;
uint8_t prev_btn_left;
uint8_t prev_btn_right;
uint8_t prev_btn_middle;
uint64_t status_recv;
} virt_mouse_t;
int virt_mouse_init(virt_mouse_t *const mouse);
int virt_mouse_get_fd(virt_mouse_t *const mouse);
int virt_mouse_send(virt_mouse_t *const mouse, mouse_status_t *const status, struct timeval *const now);
void virt_mouse_close(virt_mouse_t *const mouse);