diff --git a/app/src/control_msg.h b/app/src/control_msg.h index 2f319d9d..2d57c573 100644 --- a/app/src/control_msg.h +++ b/app/src/control_msg.h @@ -16,6 +16,7 @@ (3 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH) #define POINTER_ID_MOUSE UINT64_C(-1); +#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2); enum control_msg_type { CONTROL_MSG_TYPE_INJECT_KEYCODE, diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 2e591320..9457cc30 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -15,6 +15,9 @@ input_manager_init(struct input_manager *input_manager, input_manager->controller = controller; input_manager->video_buffer = video_buffer; input_manager->screen = screen; + + input_manager->ctrl_down = false; + input_manager->vfinger.down = false; } // Convert window coordinates (as provided by SDL_GetMouseState() to renderer @@ -221,6 +224,26 @@ clipboard_paste(struct controller *controller) { } } +static void +simulate_virtual_finger(struct input_manager *input_manager, bool down, + struct position *position) { + SDL_assert(input_manager->vfinger.down != down); + input_manager->vfinger.down = down; + + struct control_msg msg; + msg.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; + msg.inject_touch_event.action = down ? AMOTION_EVENT_ACTION_DOWN + : AMOTION_EVENT_ACTION_UP; + msg.inject_touch_event.pointer_id = POINTER_ID_VIRTUAL_FINGER; + msg.inject_touch_event.position = *position; + msg.inject_touch_event.pressure = 1.f; + msg.inject_touch_event.buttons = 0; + + if (!controller_push_msg(input_manager->controller, &msg)) { + LOGW("Could not request 'inject virtual finger event'"); + } +} + void input_manager_process_text_input(struct input_manager *input_manager, const SDL_TextInputEvent *event) { @@ -254,6 +277,14 @@ input_manager_process_key(struct input_manager *input_manager, bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI); + // store the Ctrl state to modify mouse events + input_manager->ctrl_down = ctrl; + + if (input_manager->vfinger.down && !ctrl) { + simulate_virtual_finger(input_manager, false, + &input_manager->vfinger.position); + } + // use Cmd on macOS, Ctrl on other platforms #ifdef __APPLE__ bool cmd = !ctrl && meta; @@ -437,6 +468,7 @@ input_manager_process_mouse_button(struct input_manager *input_manager, // simulated from touch events, so it's a duplicate return; } + if (event->type == SDL_MOUSEBUTTONDOWN) { if (control && event->button == SDL_BUTTON_RIGHT) { press_back_or_turn_screen_on(input_manager->controller); @@ -447,12 +479,24 @@ input_manager_process_mouse_button(struct input_manager *input_manager, return; } // double-click on black borders resize to fit the device screen - if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) { - bool outside = - is_outside_device_screen(input_manager, event->x, event->y); - if (outside) { - screen_resize_to_fit(input_manager->screen); - return; + if (event->button == SDL_BUTTON_LEFT) { + if (event->clicks >= 2) { + bool outside = + is_outside_device_screen(input_manager, event->x, event->y); + if (outside) { + screen_resize_to_fit(input_manager->screen); + return; + } + } + + struct virtual_finger *vfinger = &input_manager->vfinger; + if (input_manager->ctrl_down && !vfinger->down) { + vfinger->position.point.x = event->x; + vfinger->position.point.y = event->y; + vfinger->position.screen_size = + input_manager->screen->frame_size, + simulate_virtual_finger(input_manager, true, + &vfinger->position); } } // otherwise, send the click event to the device diff --git a/app/src/input_manager.h b/app/src/input_manager.h index 94915d7a..3be93142 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -14,6 +14,13 @@ struct input_manager { struct controller *controller; struct video_buffer *video_buffer; struct screen *screen; + + bool ctrl_down; + + struct virtual_finger { + bool down; + struct position position; + } vfinger; }; void