2018-08-15 17:01:54 +02:00
|
|
|
#include "input_manager.h"
|
2018-02-08 18:14:50 +01:00
|
|
|
|
2019-11-27 21:11:40 +01:00
|
|
|
#include <assert.h>
|
2020-07-17 00:00:42 +02:00
|
|
|
#include <SDL2/SDL_keycode.h>
|
2019-09-29 22:36:56 +02:00
|
|
|
|
2021-12-29 15:56:59 +01:00
|
|
|
#include "input_events.h"
|
2021-12-31 16:32:07 +01:00
|
|
|
#include "screen.h"
|
2019-11-24 11:53:00 +01:00
|
|
|
#include "util/log.h"
|
2018-02-08 18:14:50 +01:00
|
|
|
|
2020-07-17 00:00:42 +02:00
|
|
|
#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI)
|
|
|
|
|
|
|
|
static inline uint16_t
|
2024-03-07 23:07:01 +01:00
|
|
|
to_sdl_mod(uint8_t shortcut_mod) {
|
2020-07-17 00:00:42 +02:00
|
|
|
uint16_t sdl_mod = 0;
|
2021-12-28 15:24:15 +01:00
|
|
|
if (shortcut_mod & SC_SHORTCUT_MOD_LCTRL) {
|
2020-07-17 00:00:42 +02:00
|
|
|
sdl_mod |= KMOD_LCTRL;
|
|
|
|
}
|
2021-12-28 15:24:15 +01:00
|
|
|
if (shortcut_mod & SC_SHORTCUT_MOD_RCTRL) {
|
2020-07-17 00:00:42 +02:00
|
|
|
sdl_mod |= KMOD_RCTRL;
|
|
|
|
}
|
2021-12-28 15:24:15 +01:00
|
|
|
if (shortcut_mod & SC_SHORTCUT_MOD_LALT) {
|
2020-07-17 00:00:42 +02:00
|
|
|
sdl_mod |= KMOD_LALT;
|
|
|
|
}
|
2021-12-28 15:24:15 +01:00
|
|
|
if (shortcut_mod & SC_SHORTCUT_MOD_RALT) {
|
2020-07-17 00:00:42 +02:00
|
|
|
sdl_mod |= KMOD_RALT;
|
|
|
|
}
|
2021-12-28 15:24:15 +01:00
|
|
|
if (shortcut_mod & SC_SHORTCUT_MOD_LSUPER) {
|
2020-07-17 00:00:42 +02:00
|
|
|
sdl_mod |= KMOD_LGUI;
|
|
|
|
}
|
2021-12-28 15:24:15 +01:00
|
|
|
if (shortcut_mod & SC_SHORTCUT_MOD_RSUPER) {
|
2020-07-17 00:00:42 +02:00
|
|
|
sdl_mod |= KMOD_RGUI;
|
|
|
|
}
|
|
|
|
return sdl_mod;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2022-01-14 22:17:30 +01:00
|
|
|
is_shortcut_mod(struct sc_input_manager *im, uint16_t sdl_mod) {
|
2020-07-17 00:00:42 +02:00
|
|
|
// keep only the relevant modifier keys
|
|
|
|
sdl_mod &= SC_SDL_SHORTCUT_MODS_MASK;
|
|
|
|
|
2024-03-07 23:07:01 +01:00
|
|
|
// at least one shortcut mod pressed?
|
|
|
|
return sdl_mod & im->sdl_shortcut_mods;
|
2020-07-17 00:00:42 +02:00
|
|
|
}
|
|
|
|
|
2024-03-07 23:08:27 +01:00
|
|
|
static bool
|
|
|
|
is_shortcut_key(struct sc_input_manager *im, SDL_Keycode keycode) {
|
|
|
|
return (im->sdl_shortcut_mods & KMOD_LCTRL && keycode == SDLK_LCTRL)
|
|
|
|
|| (im->sdl_shortcut_mods & KMOD_RCTRL && keycode == SDLK_RCTRL)
|
|
|
|
|| (im->sdl_shortcut_mods & KMOD_LALT && keycode == SDLK_LALT)
|
|
|
|
|| (im->sdl_shortcut_mods & KMOD_RALT && keycode == SDLK_RALT)
|
|
|
|
|| (im->sdl_shortcut_mods & KMOD_LGUI && keycode == SDLK_LGUI)
|
|
|
|
|| (im->sdl_shortcut_mods & KMOD_RGUI && keycode == SDLK_RGUI);
|
|
|
|
}
|
|
|
|
|
2020-07-17 00:00:42 +02:00
|
|
|
void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_init(struct sc_input_manager *im,
|
|
|
|
const struct sc_input_manager_params *params) {
|
2024-01-20 18:34:33 +01:00
|
|
|
// A key/mouse processor may not be present if there is no controller
|
|
|
|
assert((!params->kp && !params->mp) || params->controller);
|
|
|
|
// A processor must have ops initialized
|
|
|
|
assert(!params->kp || params->kp->ops);
|
|
|
|
assert(!params->mp || params->mp->ops);
|
2021-12-31 16:15:41 +01:00
|
|
|
|
|
|
|
im->controller = params->controller;
|
2022-01-21 19:26:36 +01:00
|
|
|
im->fp = params->fp;
|
2021-12-31 16:15:41 +01:00
|
|
|
im->screen = params->screen;
|
|
|
|
im->kp = params->kp;
|
|
|
|
im->mp = params->mp;
|
|
|
|
|
2024-06-24 23:07:08 +02:00
|
|
|
im->mouse_bindings = params->mouse_bindings;
|
2021-12-31 16:15:41 +01:00
|
|
|
im->legacy_paste = params->legacy_paste;
|
|
|
|
im->clipboard_autosync = params->clipboard_autosync;
|
|
|
|
|
2024-03-07 23:07:01 +01:00
|
|
|
im->sdl_shortcut_mods = to_sdl_mod(params->shortcut_mods);
|
2020-08-09 16:04:02 +02:00
|
|
|
|
|
|
|
im->vfinger_down = false;
|
2023-12-13 17:04:02 +01:00
|
|
|
im->vfinger_invert_x = false;
|
|
|
|
im->vfinger_invert_y = false;
|
2021-04-17 13:15:31 +01:00
|
|
|
|
2024-07-09 18:37:53 +02:00
|
|
|
im->mouse_buttons_state = 0;
|
|
|
|
|
2021-04-17 13:15:31 +01:00
|
|
|
im->last_keycode = SDLK_UNKNOWN;
|
|
|
|
im->last_mod = 0;
|
|
|
|
im->key_repeat = 0;
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
|
|
|
|
im->next_sequence = 1; // 0 is reserved for SC_SEQUENCE_INVALID
|
2020-07-17 00:00:42 +02:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
send_keycode(struct sc_input_manager *im, enum android_keycode keycode,
|
2021-12-29 01:34:54 +01:00
|
|
|
enum sc_action action, const char *name) {
|
2024-01-20 18:34:33 +01:00
|
|
|
assert(im->controller && im->kp);
|
2024-01-20 18:19:39 +01:00
|
|
|
|
2018-02-08 18:14:50 +01:00
|
|
|
// send DOWN event
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
2021-12-29 01:34:54 +01:00
|
|
|
msg.inject_keycode.action = action == SC_ACTION_DOWN
|
|
|
|
? AKEY_EVENT_ACTION_DOWN
|
|
|
|
: AKEY_EVENT_ACTION_UP;
|
2019-05-31 14:55:11 +02:00
|
|
|
msg.inject_keycode.keycode = keycode;
|
|
|
|
msg.inject_keycode.metastate = 0;
|
2020-08-07 09:21:13 +02:00
|
|
|
msg.inject_keycode.repeat = 0;
|
2018-02-08 18:14:50 +01:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2021-12-29 01:34:54 +01:00
|
|
|
LOGW("Could not request 'inject %s'", name);
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_home(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_HOME, action, "HOME");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_back(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_BACK, action, "BACK");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_app_switch(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_APP_SWITCH, action, "APP_SWITCH");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_power(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_POWER, action, "POWER");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_volume_up(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_VOLUME_UP, action, "VOLUME_UP");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_volume_down(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_VOLUME_DOWN, action, "VOLUME_DOWN");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static inline void
|
2024-01-20 18:19:39 +01:00
|
|
|
action_menu(struct sc_input_manager *im, enum sc_action action) {
|
|
|
|
send_keycode(im, AKEYCODE_MENU, action, "MENU");
|
2018-03-20 18:04:40 -07:00
|
|
|
}
|
|
|
|
|
2018-03-10 00:11:52 +01:00
|
|
|
// turn the screen on if it was off, press BACK otherwise
|
2021-04-16 18:37:50 +02:00
|
|
|
// If the screen is off, it is turned on only on ACTION_DOWN
|
2019-03-02 20:09:56 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
press_back_or_turn_screen_on(struct sc_input_manager *im,
|
2021-12-29 01:34:54 +01:00
|
|
|
enum sc_action action) {
|
2024-01-20 18:34:33 +01:00
|
|
|
assert(im->controller && im->kp);
|
2024-01-20 18:19:39 +01:00
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
2021-12-29 01:34:54 +01:00
|
|
|
msg.back_or_screen_on.action = action == SC_ACTION_DOWN
|
|
|
|
? AKEY_EVENT_ACTION_DOWN
|
|
|
|
: AKEY_EVENT_ACTION_UP;
|
2018-03-07 14:46:31 +01:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2021-12-29 01:34:54 +01:00
|
|
|
LOGW("Could not request 'press back or turn screen on'");
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
expand_notification_panel(struct sc_input_manager *im) {
|
|
|
|
assert(im->controller);
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL;
|
2019-02-26 20:35:37 +01:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not request 'expand notification panel'");
|
2019-02-26 20:35:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-17 13:32:18 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
expand_settings_panel(struct sc_input_manager *im) {
|
|
|
|
assert(im->controller);
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL;
|
2021-04-17 13:32:18 +01:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2021-04-17 13:32:18 +01:00
|
|
|
LOGW("Could not request 'expand settings panel'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
collapse_panels(struct sc_input_manager *im) {
|
|
|
|
assert(im->controller);
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS;
|
2019-02-26 20:35:37 +01:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not request 'collapse notification panel'");
|
2019-02-26 20:35:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 09:30:57 +01:00
|
|
|
static bool
|
2024-01-20 18:19:39 +01:00
|
|
|
get_device_clipboard(struct sc_input_manager *im, enum sc_copy_key copy_key) {
|
2024-01-20 18:34:33 +01:00
|
|
|
assert(im->controller && im->kp);
|
2024-01-20 18:19:39 +01:00
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
2021-11-29 09:30:57 +01:00
|
|
|
msg.get_clipboard.copy_key = copy_key;
|
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2021-11-29 09:30:57 +01:00
|
|
|
LOGW("Could not request 'get device clipboard'");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-20 17:44:00 +01:00
|
|
|
static bool
|
2024-01-20 18:19:39 +01:00
|
|
|
set_device_clipboard(struct sc_input_manager *im, bool paste,
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
uint64_t sequence) {
|
2024-01-20 18:34:33 +01:00
|
|
|
assert(im->controller && im->kp);
|
2024-01-20 18:19:39 +01:00
|
|
|
|
2019-05-30 20:25:23 +02:00
|
|
|
char *text = SDL_GetClipboardText();
|
|
|
|
if (!text) {
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not get clipboard text: %s", SDL_GetError());
|
2021-11-20 17:44:00 +01:00
|
|
|
return false;
|
2019-05-30 20:25:23 +02:00
|
|
|
}
|
|
|
|
|
2021-01-24 15:14:53 +01:00
|
|
|
char *text_dup = strdup(text);
|
|
|
|
SDL_free(text);
|
|
|
|
if (!text_dup) {
|
|
|
|
LOGW("Could not strdup input text");
|
2021-11-20 17:44:00 +01:00
|
|
|
return false;
|
2021-01-24 15:14:53 +01:00
|
|
|
}
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_SET_CLIPBOARD;
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
msg.set_clipboard.sequence = sequence;
|
2021-01-24 15:14:53 +01:00
|
|
|
msg.set_clipboard.text = text_dup;
|
2020-05-25 20:58:24 +02:00
|
|
|
msg.set_clipboard.paste = paste;
|
2019-05-30 20:25:23 +02:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2021-01-24 15:14:53 +01:00
|
|
|
free(text_dup);
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not request 'set device clipboard'");
|
2021-11-20 17:44:00 +01:00
|
|
|
return false;
|
2019-05-30 20:25:23 +02:00
|
|
|
}
|
2021-11-20 17:44:00 +01:00
|
|
|
|
|
|
|
return true;
|
2019-05-30 20:25:23 +02:00
|
|
|
}
|
|
|
|
|
2019-03-15 20:23:30 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
set_screen_power_mode(struct sc_input_manager *im,
|
2022-01-26 21:31:30 +01:00
|
|
|
enum sc_screen_power_mode mode) {
|
2024-01-20 18:19:39 +01:00
|
|
|
assert(im->controller);
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
2019-03-15 20:23:30 +01:00
|
|
|
msg.set_screen_power_mode.mode = mode;
|
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not request 'set screen power mode'");
|
2019-03-15 20:23:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
switch_fps_counter_state(struct sc_input_manager *im) {
|
|
|
|
struct sc_fps_counter *fps_counter = &im->screen->fps_counter;
|
|
|
|
|
2019-06-07 16:55:19 +02:00
|
|
|
// the started state can only be written from the current thread, so there
|
|
|
|
// is no ToCToU issue
|
2022-02-17 19:55:14 +01:00
|
|
|
if (sc_fps_counter_is_started(fps_counter)) {
|
|
|
|
sc_fps_counter_stop(fps_counter);
|
2018-02-15 12:24:16 +01:00
|
|
|
} else {
|
2022-02-17 20:10:09 +01:00
|
|
|
sc_fps_counter_start(fps_counter);
|
|
|
|
// Any error is already logged
|
2018-02-15 12:24:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:09:56 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
clipboard_paste(struct sc_input_manager *im) {
|
2024-01-20 18:34:33 +01:00
|
|
|
assert(im->controller && im->kp);
|
2024-01-20 18:19:39 +01:00
|
|
|
|
2018-03-07 15:29:33 +01:00
|
|
|
char *text = SDL_GetClipboardText();
|
|
|
|
if (!text) {
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not get clipboard text: %s", SDL_GetError());
|
2018-03-07 15:29:33 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!*text) {
|
|
|
|
// empty text
|
|
|
|
SDL_free(text);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-24 15:14:53 +01:00
|
|
|
char *text_dup = strdup(text);
|
|
|
|
SDL_free(text);
|
|
|
|
if (!text_dup) {
|
|
|
|
LOGW("Could not strdup input text");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
|
2021-01-24 15:14:53 +01:00
|
|
|
msg.inject_text.text = text_dup;
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2021-01-24 15:14:53 +01:00
|
|
|
free(text_dup);
|
2019-06-23 20:49:38 +02:00
|
|
|
LOGW("Could not request 'paste clipboard'");
|
2018-03-07 15:29:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-04 19:55:28 +01:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
rotate_device(struct sc_input_manager *im) {
|
|
|
|
assert(im->controller);
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_ROTATE_DEVICE;
|
2019-12-04 19:55:28 +01:00
|
|
|
|
2024-01-20 18:19:39 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2019-12-04 19:55:28 +01:00
|
|
|
LOGW("Could not request device rotation");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-24 22:30:30 +01:00
|
|
|
static void
|
|
|
|
open_hard_keyboard_settings(struct sc_input_manager *im) {
|
|
|
|
assert(im->controller);
|
|
|
|
|
|
|
|
struct sc_control_msg msg;
|
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS;
|
|
|
|
|
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
|
|
|
LOGW("Could not request opening hard keyboard settings");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 23:03:23 +02:00
|
|
|
static void
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(struct sc_input_manager *im,
|
2023-11-19 01:06:59 +01:00
|
|
|
enum sc_orientation transform) {
|
2024-01-20 18:19:39 +01:00
|
|
|
struct sc_screen *screen = im->screen;
|
2023-11-19 01:06:59 +01:00
|
|
|
enum sc_orientation new_orientation =
|
|
|
|
sc_orientation_apply(screen->orientation, transform);
|
|
|
|
sc_screen_set_orientation(screen, new_orientation);
|
2020-04-07 23:03:23 +02:00
|
|
|
}
|
|
|
|
|
2021-02-15 18:53:23 +01:00
|
|
|
static void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_text_input(struct sc_input_manager *im,
|
|
|
|
const SDL_TextInputEvent *event) {
|
2021-12-30 15:03:39 +01:00
|
|
|
if (!im->kp->ops->process_text) {
|
|
|
|
// The key processor does not support text input
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-17 01:23:08 +02:00
|
|
|
if (is_shortcut_mod(im, SDL_GetModState())) {
|
|
|
|
// A shortcut must never generate text events
|
|
|
|
return;
|
|
|
|
}
|
2019-11-07 19:01:35 +01:00
|
|
|
|
2021-12-29 16:14:34 +01:00
|
|
|
struct sc_text_event evt = {
|
|
|
|
.text = event->text,
|
|
|
|
};
|
|
|
|
|
|
|
|
im->kp->ops->process_text(im->kp, &evt);
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2020-08-09 16:04:02 +02:00
|
|
|
static bool
|
2022-01-14 22:17:30 +01:00
|
|
|
simulate_virtual_finger(struct sc_input_manager *im,
|
2020-08-09 16:04:02 +02:00
|
|
|
enum android_motionevent_action action,
|
2021-10-30 15:20:39 +02:00
|
|
|
struct sc_point point) {
|
2020-08-09 16:04:02 +02:00
|
|
|
bool up = action == AMOTION_EVENT_ACTION_UP;
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
struct sc_control_msg msg;
|
2022-01-26 21:31:30 +01:00
|
|
|
msg.type = SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
2020-08-09 16:04:02 +02:00
|
|
|
msg.inject_touch_event.action = action;
|
|
|
|
msg.inject_touch_event.position.screen_size = im->screen->frame_size;
|
|
|
|
msg.inject_touch_event.position.point = point;
|
2024-07-08 16:27:59 +02:00
|
|
|
msg.inject_touch_event.pointer_id = SC_POINTER_ID_VIRTUAL_FINGER;
|
2020-08-09 16:04:02 +02:00
|
|
|
msg.inject_touch_event.pressure = up ? 0.0f : 1.0f;
|
2023-01-29 22:14:05 +01:00
|
|
|
msg.inject_touch_event.action_button = 0;
|
2020-08-09 16:04:02 +02:00
|
|
|
msg.inject_touch_event.buttons = 0;
|
|
|
|
|
2022-01-14 22:17:30 +01:00
|
|
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
2020-08-09 16:04:02 +02:00
|
|
|
LOGW("Could not request 'inject virtual finger event'");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-30 15:20:39 +02:00
|
|
|
static struct sc_point
|
2023-12-13 17:04:02 +01:00
|
|
|
inverse_point(struct sc_point point, struct sc_size size,
|
|
|
|
bool invert_x, bool invert_y) {
|
|
|
|
if (invert_x) {
|
|
|
|
point.x = size.width - point.x;
|
|
|
|
}
|
|
|
|
if (invert_y) {
|
|
|
|
point.y = size.height - point.y;
|
|
|
|
}
|
2020-08-09 16:04:02 +02:00
|
|
|
return point;
|
|
|
|
}
|
|
|
|
|
2021-02-15 18:53:23 +01:00
|
|
|
static void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_key(struct sc_input_manager *im,
|
|
|
|
const SDL_KeyboardEvent *event) {
|
2022-01-23 12:08:55 +01:00
|
|
|
// controller is NULL if --no-control is requested
|
2024-01-20 18:19:39 +01:00
|
|
|
bool control = im->controller;
|
2024-03-10 22:04:17 +01:00
|
|
|
bool paused = im->screen->paused;
|
2024-04-07 16:01:26 +02:00
|
|
|
bool video = im->screen->video;
|
2019-05-31 23:25:41 +02:00
|
|
|
|
2020-07-17 00:00:42 +02:00
|
|
|
SDL_Keycode keycode = event->keysym.sym;
|
2021-04-17 13:15:31 +01:00
|
|
|
uint16_t mod = event->keysym.mod;
|
2020-07-17 00:00:42 +02:00
|
|
|
bool down = event->type == SDL_KEYDOWN;
|
|
|
|
bool ctrl = event->keysym.mod & KMOD_CTRL;
|
|
|
|
bool shift = event->keysym.mod & KMOD_SHIFT;
|
|
|
|
bool repeat = event->repeat;
|
|
|
|
|
2024-03-07 23:08:27 +01:00
|
|
|
// Either the modifier includes a shortcut modifier, or the key
|
|
|
|
// press/release is a modifier key.
|
|
|
|
// The second condition is necessary to ignore the release of the modifier
|
|
|
|
// key (because in this case mod is 0).
|
|
|
|
bool is_shortcut = is_shortcut_mod(im, mod)
|
|
|
|
|| is_shortcut_key(im, keycode);
|
2021-04-17 13:15:31 +01:00
|
|
|
|
|
|
|
if (down && !repeat) {
|
|
|
|
if (keycode == im->last_keycode && mod == im->last_mod) {
|
|
|
|
++im->key_repeat;
|
|
|
|
} else {
|
|
|
|
im->key_repeat = 0;
|
|
|
|
im->last_keycode = keycode;
|
|
|
|
im->last_mod = mod;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-07 23:08:27 +01:00
|
|
|
if (is_shortcut) {
|
2021-12-29 01:34:54 +01:00
|
|
|
enum sc_action action = down ? SC_ACTION_DOWN : SC_ACTION_UP;
|
2018-02-08 18:14:50 +01:00
|
|
|
switch (keycode) {
|
|
|
|
case SDLK_h:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
action_home(im, action);
|
2018-06-24 21:48:34 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
|
|
|
case SDLK_b: // fall-through
|
|
|
|
case SDLK_BACKSPACE:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
action_back(im, action);
|
2018-06-24 21:48:34 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
2018-03-23 10:10:24 +01:00
|
|
|
case SDLK_s:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
action_app_switch(im, action);
|
2018-06-24 21:48:34 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
2018-03-23 10:10:24 +01:00
|
|
|
case SDLK_m:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
action_menu(im, action);
|
2018-06-24 21:48:34 +02:00
|
|
|
}
|
2018-03-20 18:04:40 -07:00
|
|
|
return;
|
2018-02-08 18:14:50 +01:00
|
|
|
case SDLK_p:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
action_power(im, action);
|
2018-06-24 21:48:34 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
2019-03-15 20:23:30 +01:00
|
|
|
case SDLK_o:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (control && !repeat && down && !paused) {
|
2022-01-26 21:31:30 +01:00
|
|
|
enum sc_screen_power_mode mode = shift
|
|
|
|
? SC_SCREEN_POWER_MODE_NORMAL
|
|
|
|
: SC_SCREEN_POWER_MODE_OFF;
|
2024-01-20 18:19:39 +01:00
|
|
|
set_screen_power_mode(im, mode);
|
2019-03-15 20:23:30 +01:00
|
|
|
}
|
|
|
|
return;
|
2024-03-10 22:04:17 +01:00
|
|
|
case SDLK_z:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && down && !repeat) {
|
2024-03-10 22:04:17 +01:00
|
|
|
sc_screen_set_paused(im->screen, !shift);
|
|
|
|
}
|
|
|
|
return;
|
2018-04-03 14:20:33 +02:00
|
|
|
case SDLK_DOWN:
|
2023-11-19 01:06:59 +01:00
|
|
|
if (shift) {
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !repeat && down) {
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(im,
|
2023-11-19 01:06:59 +01:00
|
|
|
SC_ORIENTATION_FLIP_180);
|
|
|
|
}
|
2024-03-10 22:04:17 +01:00
|
|
|
} else if (im->kp && !paused) {
|
2018-10-24 19:03:07 +02:00
|
|
|
// forward repeated events
|
2024-01-20 18:19:39 +01:00
|
|
|
action_volume_down(im, action);
|
2018-10-24 19:03:07 +02:00
|
|
|
}
|
2018-04-03 14:20:33 +02:00
|
|
|
return;
|
|
|
|
case SDLK_UP:
|
2023-11-19 01:06:59 +01:00
|
|
|
if (shift) {
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !repeat && down) {
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(im,
|
2023-11-19 01:06:59 +01:00
|
|
|
SC_ORIENTATION_FLIP_180);
|
|
|
|
}
|
2024-03-10 22:04:17 +01:00
|
|
|
} else if (im->kp && !paused) {
|
2018-10-24 19:03:07 +02:00
|
|
|
// forward repeated events
|
2024-01-20 18:19:39 +01:00
|
|
|
action_volume_up(im, action);
|
2018-10-24 19:03:07 +02:00
|
|
|
}
|
2018-04-03 14:20:33 +02:00
|
|
|
return;
|
2020-04-07 23:03:23 +02:00
|
|
|
case SDLK_LEFT:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !repeat && down) {
|
2023-11-19 01:06:59 +01:00
|
|
|
if (shift) {
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(im,
|
2023-11-19 01:06:59 +01:00
|
|
|
SC_ORIENTATION_FLIP_0);
|
|
|
|
} else {
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(im,
|
2023-11-19 01:06:59 +01:00
|
|
|
SC_ORIENTATION_270);
|
|
|
|
}
|
2020-04-07 23:03:23 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
case SDLK_RIGHT:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !repeat && down) {
|
2023-11-19 01:06:59 +01:00
|
|
|
if (shift) {
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(im,
|
2023-11-19 01:06:59 +01:00
|
|
|
SC_ORIENTATION_FLIP_0);
|
|
|
|
} else {
|
2024-01-20 18:19:39 +01:00
|
|
|
apply_orientation_transform(im,
|
2023-11-19 01:06:59 +01:00
|
|
|
SC_ORIENTATION_90);
|
|
|
|
}
|
2020-04-07 23:03:23 +02:00
|
|
|
}
|
|
|
|
return;
|
2020-07-17 00:00:42 +02:00
|
|
|
case SDLK_c:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && down && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
get_device_clipboard(im, SC_COPY_KEY_COPY);
|
2020-07-17 00:00:42 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
case SDLK_x:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !shift && !repeat && down && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
get_device_clipboard(im, SC_COPY_KEY_CUT);
|
2020-07-17 00:00:42 +02:00
|
|
|
}
|
|
|
|
return;
|
2018-03-07 15:29:33 +01:00
|
|
|
case SDLK_v:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (im->kp && !repeat && down && !paused) {
|
2020-10-06 21:30:10 +02:00
|
|
|
if (shift || im->legacy_paste) {
|
2019-05-30 20:25:23 +02:00
|
|
|
// inject the text as input events
|
2024-01-20 18:19:39 +01:00
|
|
|
clipboard_paste(im);
|
2020-07-17 00:00:42 +02:00
|
|
|
} else {
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
// store the text in the device clipboard and paste,
|
|
|
|
// without requesting an acknowledgment
|
2024-01-20 18:19:39 +01:00
|
|
|
set_device_clipboard(im, true, SC_SEQUENCE_INVALID);
|
2019-05-30 20:25:23 +02:00
|
|
|
}
|
2018-06-24 21:09:23 +02:00
|
|
|
}
|
2018-03-07 15:29:33 +01:00
|
|
|
return;
|
2018-02-08 18:14:50 +01:00
|
|
|
case SDLK_f:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !shift && !repeat && down) {
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_screen_switch_fullscreen(im->screen);
|
2018-06-24 21:09:23 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
2020-07-17 00:00:42 +02:00
|
|
|
case SDLK_w:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !shift && !repeat && down) {
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_screen_resize_to_fit(im->screen);
|
2018-06-24 21:09:23 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
|
|
|
case SDLK_g:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !shift && !repeat && down) {
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_screen_resize_to_pixel_perfect(im->screen);
|
2018-06-24 21:09:23 +02:00
|
|
|
}
|
2018-02-08 18:14:50 +01:00
|
|
|
return;
|
2018-02-15 12:24:16 +01:00
|
|
|
case SDLK_i:
|
2024-04-07 16:01:26 +02:00
|
|
|
if (video && !shift && !repeat && down) {
|
2024-01-20 18:19:39 +01:00
|
|
|
switch_fps_counter_state(im);
|
2018-06-24 21:09:23 +02:00
|
|
|
}
|
2019-02-26 20:35:37 +01:00
|
|
|
return;
|
|
|
|
case SDLK_n:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (control && !repeat && down && !paused) {
|
2019-02-26 20:35:37 +01:00
|
|
|
if (shift) {
|
2024-01-20 18:19:39 +01:00
|
|
|
collapse_panels(im);
|
2021-04-20 18:31:39 +02:00
|
|
|
} else if (im->key_repeat == 0) {
|
2024-01-20 18:19:39 +01:00
|
|
|
expand_notification_panel(im);
|
2021-04-20 18:31:39 +02:00
|
|
|
} else {
|
2024-01-20 18:19:39 +01:00
|
|
|
expand_settings_panel(im);
|
2019-02-26 20:35:37 +01:00
|
|
|
}
|
|
|
|
}
|
2018-02-15 12:24:16 +01:00
|
|
|
return;
|
2019-12-04 19:55:28 +01:00
|
|
|
case SDLK_r:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (control && !shift && !repeat && down && !paused) {
|
2024-01-20 18:19:39 +01:00
|
|
|
rotate_device(im);
|
2019-12-04 19:55:28 +01:00
|
|
|
}
|
|
|
|
return;
|
2024-02-24 22:30:30 +01:00
|
|
|
case SDLK_k:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (control && !shift && !repeat && down && !paused
|
2024-02-24 22:30:30 +01:00
|
|
|
&& im->kp && im->kp->hid) {
|
|
|
|
// Only if the current keyboard is hid
|
|
|
|
open_hard_keyboard_settings(im);
|
|
|
|
}
|
|
|
|
return;
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-10 22:04:17 +01:00
|
|
|
if (!im->kp || paused) {
|
2019-03-02 22:40:51 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
uint64_t ack_to_wait = SC_SEQUENCE_INVALID;
|
2021-11-21 17:24:34 +01:00
|
|
|
bool is_ctrl_v = ctrl && !shift && keycode == SDLK_v && down && !repeat;
|
2021-11-22 08:49:10 +01:00
|
|
|
if (im->clipboard_autosync && is_ctrl_v) {
|
2020-10-06 21:30:10 +02:00
|
|
|
if (im->legacy_paste) {
|
|
|
|
// inject the text as input events
|
2024-01-20 18:19:39 +01:00
|
|
|
clipboard_paste(im);
|
2020-10-06 21:30:10 +02:00
|
|
|
return;
|
|
|
|
}
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
|
|
|
|
// Request an acknowledgement only if necessary
|
|
|
|
uint64_t sequence = im->kp->async_paste ? im->next_sequence
|
|
|
|
: SC_SEQUENCE_INVALID;
|
|
|
|
|
2020-07-17 00:00:42 +02:00
|
|
|
// Synchronize the computer clipboard to the device clipboard before
|
|
|
|
// sending Ctrl+v, to allow seamless copy-paste.
|
2024-01-20 18:19:39 +01:00
|
|
|
bool ok = set_device_clipboard(im, false, sequence);
|
2021-11-20 17:44:00 +01:00
|
|
|
if (!ok) {
|
|
|
|
LOGW("Clipboard could not be synchronized, Ctrl+v not injected");
|
|
|
|
return;
|
|
|
|
}
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-21 17:40:11 +01:00
|
|
|
|
|
|
|
if (im->kp->async_paste) {
|
|
|
|
// The key processor must wait for this ack before injecting Ctrl+v
|
|
|
|
ack_to_wait = sequence;
|
|
|
|
// Increment only when the request succeeded
|
|
|
|
++im->next_sequence;
|
|
|
|
}
|
2020-07-17 00:00:42 +02:00
|
|
|
}
|
|
|
|
|
2021-12-29 16:14:34 +01:00
|
|
|
struct sc_key_event evt = {
|
|
|
|
.action = sc_action_from_sdl_keyboard_type(event->type),
|
|
|
|
.keycode = sc_keycode_from_sdl(event->keysym.sym),
|
|
|
|
.scancode = sc_scancode_from_sdl(event->keysym.scancode),
|
|
|
|
.repeat = event->repeat,
|
|
|
|
.mods_state = sc_mods_state_from_sdl(event->keysym.mod),
|
|
|
|
};
|
|
|
|
|
2021-12-30 15:03:39 +01:00
|
|
|
assert(im->kp->ops->process_key);
|
2021-12-29 16:14:34 +01:00
|
|
|
im->kp->ops->process_key(im->kp, &evt, ack_to_wait);
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:01:26 +02:00
|
|
|
static struct sc_position
|
|
|
|
sc_input_manager_get_position(struct sc_input_manager *im, int32_t x,
|
|
|
|
int32_t y) {
|
|
|
|
if (im->mp->relative_mode) {
|
|
|
|
// No absolute position
|
|
|
|
return (struct sc_position) {
|
|
|
|
.screen_size = {0, 0},
|
|
|
|
.point = {0, 0},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return (struct sc_position) {
|
|
|
|
.screen_size = im->screen->frame_size,
|
|
|
|
.point = sc_screen_convert_window_to_frame_coords(im->screen, x, y),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-02-15 18:53:23 +01:00
|
|
|
static void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
|
|
|
const SDL_MouseMotionEvent *event) {
|
2019-09-22 21:33:16 +02:00
|
|
|
if (event->which == SDL_TOUCH_MOUSEID) {
|
|
|
|
// simulated from touch events, so it's a duplicate
|
|
|
|
return;
|
|
|
|
}
|
2020-08-09 16:04:02 +02:00
|
|
|
|
2021-12-29 16:24:20 +01:00
|
|
|
struct sc_mouse_motion_event evt = {
|
2024-04-07 16:01:26 +02:00
|
|
|
.position = sc_input_manager_get_position(im, event->x, event->y),
|
2024-07-08 16:27:59 +02:00
|
|
|
.pointer_id = im->vfinger_down ? SC_POINTER_ID_GENERIC_FINGER
|
|
|
|
: SC_POINTER_ID_MOUSE,
|
2021-12-30 00:05:30 +01:00
|
|
|
.xrel = event->xrel,
|
|
|
|
.yrel = event->yrel,
|
2024-07-09 18:37:53 +02:00
|
|
|
.buttons_state = im->mouse_buttons_state,
|
2021-12-29 16:24:20 +01:00
|
|
|
};
|
|
|
|
|
2021-12-30 15:08:42 +01:00
|
|
|
assert(im->mp->ops->process_mouse_motion);
|
2021-12-29 16:24:20 +01:00
|
|
|
im->mp->ops->process_mouse_motion(im->mp, &evt);
|
2020-08-09 16:04:02 +02:00
|
|
|
|
2021-12-30 15:46:00 +01:00
|
|
|
// vfinger must never be used in relative mode
|
|
|
|
assert(!im->mp->relative_mode || !im->vfinger_down);
|
|
|
|
|
2020-08-09 16:04:02 +02:00
|
|
|
if (im->vfinger_down) {
|
2021-12-30 15:46:00 +01:00
|
|
|
assert(!im->mp->relative_mode); // assert one more time
|
2021-10-30 15:20:39 +02:00
|
|
|
struct sc_point mouse =
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
|
|
|
event->y);
|
2023-12-13 17:04:02 +01:00
|
|
|
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size,
|
|
|
|
im->vfinger_invert_x,
|
|
|
|
im->vfinger_invert_y);
|
2020-08-09 16:04:02 +02:00
|
|
|
simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger);
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 18:53:23 +01:00
|
|
|
static void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_touch(struct sc_input_manager *im,
|
|
|
|
const SDL_TouchFingerEvent *event) {
|
2021-12-30 15:08:42 +01:00
|
|
|
if (!im->mp->ops->process_touch) {
|
|
|
|
// The mouse processor does not support touch events
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-29 16:24:20 +01:00
|
|
|
int dw;
|
|
|
|
int dh;
|
|
|
|
SDL_GL_GetDrawableSize(im->screen->window, &dw, &dh);
|
|
|
|
|
|
|
|
// SDL touch event coordinates are normalized in the range [0; 1]
|
|
|
|
int32_t x = event->x * dw;
|
|
|
|
int32_t y = event->y * dh;
|
|
|
|
|
|
|
|
struct sc_touch_event evt = {
|
|
|
|
.position = {
|
|
|
|
.screen_size = im->screen->frame_size,
|
2022-01-14 22:17:30 +01:00
|
|
|
.point =
|
|
|
|
sc_screen_convert_drawable_to_frame_coords(im->screen, x, y),
|
2021-12-29 16:24:20 +01:00
|
|
|
},
|
|
|
|
.action = sc_touch_action_from_sdl(event->type),
|
|
|
|
.pointer_id = event->fingerId,
|
|
|
|
.pressure = event->pressure,
|
|
|
|
};
|
|
|
|
|
|
|
|
im->mp->ops->process_touch(im->mp, &evt);
|
2019-10-20 12:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-06-24 23:07:08 +02:00
|
|
|
static enum sc_mouse_binding
|
2024-07-09 20:45:49 +02:00
|
|
|
sc_input_manager_get_binding(const struct sc_mouse_binding_set *bindings,
|
2024-06-24 23:07:08 +02:00
|
|
|
uint8_t sdl_button) {
|
|
|
|
switch (sdl_button) {
|
|
|
|
case SDL_BUTTON_LEFT:
|
|
|
|
return SC_MOUSE_BINDING_CLICK;
|
|
|
|
case SDL_BUTTON_RIGHT:
|
|
|
|
return bindings->right_click;
|
|
|
|
case SDL_BUTTON_MIDDLE:
|
|
|
|
return bindings->middle_click;
|
|
|
|
case SDL_BUTTON_X1:
|
|
|
|
return bindings->click4;
|
|
|
|
case SDL_BUTTON_X2:
|
|
|
|
return bindings->click5;
|
|
|
|
default:
|
|
|
|
return SC_MOUSE_BINDING_DISABLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 18:53:23 +01:00
|
|
|
static void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
|
|
|
const SDL_MouseButtonEvent *event) {
|
2019-09-22 21:33:16 +02:00
|
|
|
if (event->which == SDL_TOUCH_MOUSEID) {
|
|
|
|
// simulated from touch events, so it's a duplicate
|
|
|
|
return;
|
|
|
|
}
|
2020-08-09 16:04:02 +02:00
|
|
|
|
2024-03-10 22:04:17 +01:00
|
|
|
bool control = im->controller;
|
|
|
|
bool paused = im->screen->paused;
|
2020-08-09 16:04:02 +02:00
|
|
|
bool down = event->type == SDL_MOUSEBUTTONDOWN;
|
2024-07-09 18:37:53 +02:00
|
|
|
|
|
|
|
enum sc_mouse_button button = sc_mouse_button_from_sdl(event->button);
|
|
|
|
if (!down) {
|
|
|
|
// Mark the button as released
|
|
|
|
im->mouse_buttons_state &= ~button;
|
|
|
|
}
|
|
|
|
|
2024-07-09 20:45:49 +02:00
|
|
|
SDL_Keymod keymod = SDL_GetModState();
|
|
|
|
bool ctrl_pressed = keymod & KMOD_CTRL;
|
|
|
|
bool shift_pressed = keymod & KMOD_SHIFT;
|
|
|
|
|
2024-06-24 23:07:08 +02:00
|
|
|
if (control && !paused) {
|
2024-06-24 23:00:33 +02:00
|
|
|
enum sc_action action = down ? SC_ACTION_DOWN : SC_ACTION_UP;
|
2021-04-16 17:58:22 +02:00
|
|
|
|
2024-07-09 20:45:49 +02:00
|
|
|
struct sc_mouse_binding_set *bindings = !shift_pressed
|
|
|
|
? &im->mouse_bindings.pri
|
|
|
|
: &im->mouse_bindings.sec;
|
2024-06-24 23:07:08 +02:00
|
|
|
enum sc_mouse_binding binding =
|
2024-07-09 20:45:49 +02:00
|
|
|
sc_input_manager_get_binding(bindings, event->button);
|
2024-06-24 23:11:42 +02:00
|
|
|
assert(binding != SC_MOUSE_BINDING_AUTO);
|
2024-06-24 23:07:08 +02:00
|
|
|
switch (binding) {
|
|
|
|
case SC_MOUSE_BINDING_DISABLED:
|
|
|
|
// ignore click
|
|
|
|
return;
|
|
|
|
case SC_MOUSE_BINDING_BACK:
|
|
|
|
if (im->kp) {
|
|
|
|
press_back_or_turn_screen_on(im, action);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case SC_MOUSE_BINDING_HOME:
|
|
|
|
if (im->kp) {
|
|
|
|
action_home(im, action);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case SC_MOUSE_BINDING_APP_SWITCH:
|
|
|
|
if (im->kp) {
|
|
|
|
action_app_switch(im, action);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case SC_MOUSE_BINDING_EXPAND_NOTIFICATION_PANEL:
|
|
|
|
if (down) {
|
|
|
|
if (event->clicks < 2) {
|
|
|
|
expand_notification_panel(im);
|
|
|
|
} else {
|
|
|
|
expand_settings_panel(im);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
assert(binding == SC_MOUSE_BINDING_CLICK);
|
|
|
|
break;
|
2024-06-24 23:00:33 +02:00
|
|
|
}
|
|
|
|
}
|
2020-04-17 18:44:24 +02:00
|
|
|
|
2024-06-24 23:00:33 +02:00
|
|
|
// double-click on black borders resizes to fit the device screen
|
|
|
|
bool video = im->screen->video;
|
|
|
|
bool mouse_relative_mode = im->mp && im->mp->relative_mode;
|
|
|
|
if (video && !mouse_relative_mode && event->button == SDL_BUTTON_LEFT
|
|
|
|
&& event->clicks == 2) {
|
|
|
|
int32_t x = event->x;
|
|
|
|
int32_t y = event->y;
|
|
|
|
sc_screen_hidpi_scale_coords(im->screen, &x, &y);
|
|
|
|
SDL_Rect *r = &im->screen->rect;
|
|
|
|
bool outside = x < r->x || x >= r->x + r->w
|
|
|
|
|| y < r->y || y >= r->y + r->h;
|
|
|
|
if (outside) {
|
|
|
|
if (down) {
|
|
|
|
sc_screen_resize_to_fit(im->screen);
|
2018-11-27 08:54:31 +01:00
|
|
|
}
|
2024-06-24 23:00:33 +02:00
|
|
|
return;
|
2018-03-13 08:32:48 +01:00
|
|
|
}
|
2018-08-11 21:06:38 +08:00
|
|
|
}
|
2018-11-18 21:20:21 +01:00
|
|
|
|
2024-03-10 22:04:17 +01:00
|
|
|
if (!im->mp || paused) {
|
2019-03-02 22:40:51 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-07-09 18:37:53 +02:00
|
|
|
if (down) {
|
|
|
|
// Mark the button as pressed
|
|
|
|
im->mouse_buttons_state |= button;
|
|
|
|
}
|
2021-12-29 16:24:20 +01:00
|
|
|
|
2024-07-08 16:27:59 +02:00
|
|
|
bool change_vfinger = event->button == SDL_BUTTON_LEFT &&
|
|
|
|
((down && !im->vfinger_down && (ctrl_pressed ^ shift_pressed)) ||
|
|
|
|
(!down && im->vfinger_down));
|
|
|
|
bool use_finger = im->vfinger_down || change_vfinger;
|
|
|
|
|
2021-12-29 16:24:20 +01:00
|
|
|
struct sc_mouse_click_event evt = {
|
2024-04-07 16:01:26 +02:00
|
|
|
.position = sc_input_manager_get_position(im, event->x, event->y),
|
2021-12-29 16:24:20 +01:00
|
|
|
.action = sc_action_from_sdl_mousebutton_type(event->type),
|
|
|
|
.button = sc_mouse_button_from_sdl(event->button),
|
2024-07-08 16:27:59 +02:00
|
|
|
.pointer_id = use_finger ? SC_POINTER_ID_GENERIC_FINGER
|
|
|
|
: SC_POINTER_ID_MOUSE,
|
2024-07-09 18:37:53 +02:00
|
|
|
.buttons_state = im->mouse_buttons_state,
|
2021-12-29 16:24:20 +01:00
|
|
|
};
|
|
|
|
|
2021-12-30 15:08:42 +01:00
|
|
|
assert(im->mp->ops->process_mouse_click);
|
2021-12-29 16:24:20 +01:00
|
|
|
im->mp->ops->process_mouse_click(im->mp, &evt);
|
2020-08-09 16:04:02 +02:00
|
|
|
|
2021-12-30 15:46:00 +01:00
|
|
|
if (im->mp->relative_mode) {
|
|
|
|
assert(!im->vfinger_down); // vfinger must not be used in relative mode
|
|
|
|
// No pinch-to-zoom simulation
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-13 17:04:02 +01:00
|
|
|
// Pinch-to-zoom, rotate and tilt simulation.
|
2020-08-09 16:04:02 +02:00
|
|
|
//
|
|
|
|
// If Ctrl is hold when the left-click button is pressed, then
|
|
|
|
// pinch-to-zoom mode is enabled: on every mouse event until the left-click
|
|
|
|
// button is released, an additional "virtual finger" event is generated,
|
|
|
|
// having a position inverted through the center of the screen.
|
|
|
|
//
|
|
|
|
// In other words, the center of the rotation/scaling is the center of the
|
|
|
|
// screen.
|
2023-12-13 17:04:02 +01:00
|
|
|
//
|
|
|
|
// To simulate a tilt gesture (a vertical slide with two fingers), Shift
|
|
|
|
// can be used instead of Ctrl. The "virtual finger" has a position
|
|
|
|
// inverted with respect to the vertical axis of symmetry in the middle of
|
|
|
|
// the screen.
|
2024-07-08 16:27:59 +02:00
|
|
|
if (change_vfinger) {
|
2021-10-30 15:20:39 +02:00
|
|
|
struct sc_point mouse =
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_screen_convert_window_to_frame_coords(im->screen, event->x,
|
|
|
|
event->y);
|
2023-12-13 17:04:02 +01:00
|
|
|
if (down) {
|
|
|
|
im->vfinger_invert_x = ctrl_pressed || shift_pressed;
|
|
|
|
im->vfinger_invert_y = ctrl_pressed;
|
|
|
|
}
|
|
|
|
struct sc_point vfinger = inverse_point(mouse, im->screen->frame_size,
|
|
|
|
im->vfinger_invert_x,
|
|
|
|
im->vfinger_invert_y);
|
2020-08-09 16:04:02 +02:00
|
|
|
enum android_motionevent_action action = down
|
|
|
|
? AMOTION_EVENT_ACTION_DOWN
|
|
|
|
: AMOTION_EVENT_ACTION_UP;
|
|
|
|
if (!simulate_virtual_finger(im, action, vfinger)) {
|
|
|
|
return;
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
2020-08-09 16:04:02 +02:00
|
|
|
im->vfinger_down = down;
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 18:53:23 +01:00
|
|
|
static void
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
|
|
|
|
const SDL_MouseWheelEvent *event) {
|
2021-12-30 15:08:42 +01:00
|
|
|
if (!im->mp->ops->process_mouse_scroll) {
|
|
|
|
// The mouse processor does not support scroll events
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-29 16:24:20 +01:00
|
|
|
// mouse_x and mouse_y are expressed in pixels relative to the window
|
|
|
|
int mouse_x;
|
|
|
|
int mouse_y;
|
2021-12-31 10:38:05 +01:00
|
|
|
uint32_t buttons = SDL_GetMouseState(&mouse_x, &mouse_y);
|
2024-07-09 18:37:53 +02:00
|
|
|
(void) buttons; // Actual buttons are tracked manually to ignore shortcuts
|
2021-12-29 16:24:20 +01:00
|
|
|
|
|
|
|
struct sc_mouse_scroll_event evt = {
|
2024-04-07 16:01:26 +02:00
|
|
|
.position = sc_input_manager_get_position(im, mouse_x, mouse_y),
|
2022-07-03 07:02:17 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
|
|
|
.hscroll = CLAMP(event->preciseX, -1.0f, 1.0f),
|
|
|
|
.vscroll = CLAMP(event->preciseY, -1.0f, 1.0f),
|
|
|
|
#else
|
|
|
|
.hscroll = CLAMP(event->x, -1, 1),
|
|
|
|
.vscroll = CLAMP(event->y, -1, 1),
|
|
|
|
#endif
|
2024-07-09 18:37:53 +02:00
|
|
|
.buttons_state = im->mouse_buttons_state,
|
2021-12-29 16:24:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
im->mp->ops->process_mouse_scroll(im->mp, &evt);
|
2018-02-08 18:14:50 +01:00
|
|
|
}
|
2021-02-15 18:53:23 +01:00
|
|
|
|
2022-01-21 19:26:36 +01:00
|
|
|
static bool
|
|
|
|
is_apk(const char *file) {
|
|
|
|
const char *ext = strrchr(file, '.');
|
|
|
|
return ext && !strcmp(ext, ".apk");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sc_input_manager_process_file(struct sc_input_manager *im,
|
|
|
|
const SDL_DropEvent *event) {
|
|
|
|
char *file = strdup(event->file);
|
|
|
|
SDL_free(event->file);
|
|
|
|
if (!file) {
|
|
|
|
LOG_OOM();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum sc_file_pusher_action action;
|
|
|
|
if (is_apk(file)) {
|
|
|
|
action = SC_FILE_PUSHER_ACTION_INSTALL_APK;
|
|
|
|
} else {
|
|
|
|
action = SC_FILE_PUSHER_ACTION_PUSH_FILE;
|
|
|
|
}
|
|
|
|
bool ok = sc_file_pusher_request(im->fp, action, file);
|
|
|
|
if (!ok) {
|
|
|
|
free(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-21 19:16:32 +01:00
|
|
|
void
|
2023-04-03 21:41:54 +02:00
|
|
|
sc_input_manager_handle_event(struct sc_input_manager *im,
|
|
|
|
const SDL_Event *event) {
|
2022-01-23 12:08:55 +01:00
|
|
|
bool control = im->controller;
|
2024-03-10 22:04:17 +01:00
|
|
|
bool paused = im->screen->paused;
|
2021-02-15 18:53:23 +01:00
|
|
|
switch (event->type) {
|
|
|
|
case SDL_TEXTINPUT:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (!im->kp || paused) {
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2021-02-15 18:53:23 +01:00
|
|
|
}
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_text_input(im, &event->text);
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2021-02-15 18:53:23 +01:00
|
|
|
case SDL_KEYDOWN:
|
|
|
|
case SDL_KEYUP:
|
|
|
|
// some key events do not interact with the device, so process the
|
|
|
|
// event even if control is disabled
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_key(im, &event->key);
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2021-02-15 18:53:23 +01:00
|
|
|
case SDL_MOUSEMOTION:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (!im->mp || paused) {
|
2021-02-15 18:53:23 +01:00
|
|
|
break;
|
|
|
|
}
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_mouse_motion(im, &event->motion);
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2021-02-15 18:53:23 +01:00
|
|
|
case SDL_MOUSEWHEEL:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (!im->mp || paused) {
|
2021-02-15 18:53:23 +01:00
|
|
|
break;
|
|
|
|
}
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_mouse_wheel(im, &event->wheel);
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2021-02-15 18:53:23 +01:00
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
// some mouse events do not interact with the device, so process
|
|
|
|
// the event even if control is disabled
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_mouse_button(im, &event->button);
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2021-02-15 18:53:23 +01:00
|
|
|
case SDL_FINGERMOTION:
|
|
|
|
case SDL_FINGERDOWN:
|
|
|
|
case SDL_FINGERUP:
|
2024-03-10 22:04:17 +01:00
|
|
|
if (!im->mp || paused) {
|
2022-01-23 12:02:35 +01:00
|
|
|
break;
|
|
|
|
}
|
2022-01-14 22:17:30 +01:00
|
|
|
sc_input_manager_process_touch(im, &event->tfinger);
|
2022-01-21 19:16:32 +01:00
|
|
|
break;
|
2022-01-21 19:26:36 +01:00
|
|
|
case SDL_DROPFILE: {
|
2022-01-23 12:08:55 +01:00
|
|
|
if (!control) {
|
2022-01-21 19:26:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc_input_manager_process_file(im, &event->drop);
|
|
|
|
}
|
2021-02-15 18:53:23 +01:00
|
|
|
}
|
|
|
|
}
|