From 0b7f888a2fc1a1ce20c25eb2dc39a5352920196f Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 16 Dec 2023 22:10:57 +0100 Subject: [PATCH 1/2] Implementing virtual mouse and mode switch --- CMakeLists.txt | 2 + dev_out.c | 366 ++++++++++++++++++++++++++++------------------- devices_status.c | 12 +- devices_status.h | 17 +++ message.h | 16 +++ rog_ally.c | 72 +++++++++- virt_mouse.c | 141 ++++++++++++++++++ virt_mouse.h | 29 ++++ 8 files changed, 502 insertions(+), 153 deletions(-) create mode 100644 virt_mouse.c create mode 100644 virt_mouse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d85d929..30e3c1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/dev_out.c b/dev_out.c index 8ac09a9..8f121b0 100644 --- a/dev_out.c +++ b/dev_out.c @@ -5,6 +5,7 @@ #include "message.h" #include "virt_ds4.h" #include "virt_ds5.h" +#include "virt_mouse.h" #include @@ -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 diff --git a/devices_status.c b/devices_status.c index bd67963..14e38c8 100644 --- a/devices_status.c +++ b/devices_status.c @@ -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) { diff --git a/devices_status.h b/devices_status.h index 8d39b26..869e7a7 100644 --- a/devices_status.h +++ b/devices_status.h @@ -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); diff --git a/message.h b/message.h index d16e371..372c124 100644 --- a/message.h +++ b/message.h @@ -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; diff --git a/rog_ally.c b/rog_ally.c index 02a891f..f7ac59e 100644 --- a/rog_ally.c +++ b/rog_ally.c @@ -1,7 +1,9 @@ #include "rog_ally.h" #include "input_dev.h" #include "dev_hidraw.h" +#include "message.h" #include "xbox360.h" +#include 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; } } } diff --git a/virt_mouse.c b/virt_mouse.c new file mode 100644 index 0000000..add0a18 --- /dev/null +++ b/virt_mouse.c @@ -0,0 +1,141 @@ +#include "virt_mouse.h" +#include +#include +#include + +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); +} \ No newline at end of file diff --git a/virt_mouse.h b/virt_mouse.h new file mode 100644 index 0000000..1ac8da5 --- /dev/null +++ b/virt_mouse.h @@ -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); \ No newline at end of file From cc16d4983e27d258692485973fd43eb77b0a8262 Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 16 Dec 2023 22:26:37 +0100 Subject: [PATCH 2/2] mode switch should work --- rog_ally.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/rog_ally.c b/rog_ally.c index f7ac59e..0c59607 100644 --- a/rog_ally.c +++ b/rog_ally.c @@ -4,6 +4,7 @@ #include "message.h" #include "xbox360.h" #include +#include typedef enum rc71l_platform_mode { rc71l_platform_mode_hidraw, @@ -83,7 +84,11 @@ static char* find_kernel_sysfs_device_path(struct udev *udev) { return NULL; } -int asus_kbd_ev_map( +static int get_next_mode(int current_mode) { + return 1 + ((current_mode + 1) % 3); +} + +static int asus_kbd_ev_map( const dev_in_settings_t *const conf, const evdev_collected_t *const e, in_message_t *const messages, @@ -167,6 +172,53 @@ int asus_kbd_ev_map( printf("Asus MCU kernel interface found at %s -- switching mode\n", kernel_sysfs); + const size_t tmp_path_max_len = strlen(kernel_sysfs) + 256; + char *tmp_path = malloc(tmp_path_max_len); + + if (tmp_path != NULL) { + memset(tmp_path, 0, tmp_path_max_len); + snprintf(tmp_path, tmp_path_max_len - 1, "%s/gamepad_mode", kernel_sysfs); + + int gamepad_mode_fd = open(tmp_path, O_RDONLY | O_NONBLOCK); + if (gamepad_mode_fd > 0) { + char current_mode_str[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int current_mode_read_res = read(gamepad_mode_fd, (void*)current_mode_str, sizeof(current_mode_str)); + if (current_mode_read_res > 0) { + int current_mode; + sscanf("%d", current_mode_str, ¤t_mode); + + const int new_mode = get_next_mode(current_mode); + printf("Current mode is set to %d -- switching to %d", current_mode, new_mode); + + // end the current mode read + close(gamepad_mode_fd); + + char new_mode_str[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + snprintf(new_mode_str, sizeof(new_mode_str) - 1, "%d", new_mode); + gamepad_mode_fd = open(tmp_path, O_RDONLY); + if (gamepad_mode_fd > 0) { + if (write(gamepad_mode_fd, new_mode_str, strlen(new_mode_str)) > 0) { + printf("Controller mode switched successfully to %d\n", new_mode); + } else { + fprintf(stderr, "Unable to switch controller mode: %d -- expect bugs\n", errno); + } + close(gamepad_mode_fd); + } else { + fprintf(stderr, "Unable to open gamepad mode file to switch mode: %d\n", errno); + } + } else { + close(gamepad_mode_fd); + fprintf(stderr, "Unable to read gamepad_mode file to get current mode: %d", errno); + } + } else { + fprintf(stderr, "Unable to open gamepad_mode file in read-only mode to get current mode: %d", errno); + } + + free(tmp_path); + } else { + fprintf(stderr, "Unable to allocate enough memory\n"); + } + free(kernel_sysfs); } else if (e->ev[i].code == BTN_LEFT) { const in_message_t current_message = {