Skip to content

Commit c3119e7

Browse files
committed
Supports fake touch on /dev/input/wl_touch_events
persist.waydroid.fake_touch is implemented at a higher level, making it more flexible as it allows enabling fake touch for specific Android applications. However, its implementation may not work for some Android applications (e.g., xuexi_android_10002068.apk). By implementing fake events in /dev/input/wl_touch_events, it can cover a wider range of cases. Regardless of how the upper-layer Android applications behave, fake events through /dev/input/* will always take effect. Fixes: waydroid/waydroid#954
1 parent 587b45f commit c3119e7

File tree

2 files changed

+109
-3
lines changed

2 files changed

+109
-3
lines changed

hwcomposer/wayland-hwc.cpp

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <stdlib.h>
3535
#include <stdbool.h>
3636
#include <assert.h>
37+
#include <string>
3738
#include <unistd.h>
3839
#include <sys/mman.h>
3940
#include <sys/stat.h>
@@ -78,6 +79,8 @@ using ::android::hardware::hidl_string;
7879

7980
struct buffer;
8081

82+
#define FAKE_TOUCH_ID 1111
83+
8184
void
8285
destroy_buffer(struct buffer* buf) {
8386
wl_buffer_destroy(buf->buffer);
@@ -812,28 +815,48 @@ static const struct wl_keyboard_listener keyboard_listener = {
812815
static void
813816
pointer_handle_enter(void *data, struct wl_pointer *pointer,
814817
uint32_t serial, struct wl_surface *surface,
815-
wl_fixed_t, wl_fixed_t)
818+
wl_fixed_t sx, wl_fixed_t sy)
816819
{
820+
ALOGI("Pointer enter event: serial=%u, surface=%p, sx=%f, sy=%f",
821+
serial, surface, wl_fixed_to_double(sx), wl_fixed_to_double(sy));
817822
struct display *display = (struct display *)data;
818823
display->pointer_surface = surface;
824+
825+
if (display->pointer_surface) {
826+
display->pointer_surface_sx = sx;
827+
display->pointer_surface_sy = sy;
828+
}
829+
819830
if (display->cursor_surface)
820831
wl_pointer_set_cursor(pointer, serial,
821832
display->cursor_surface, 0, 0);
822833
}
823834

835+
static void
836+
touch_handle_cancel(void *data, struct wl_touch *);
824837
static void
825838
pointer_handle_leave(void *data, struct wl_pointer *pointer,
826839
uint32_t serial, struct wl_surface *)
827840
{
841+
ALOGI("Pointer leave event: serial=%u, surface=%p", serial, nullptr);
828842
struct display *display = (struct display *)data;
843+
844+
if (display->fakeTouchEnabled) {
845+
display->fakeTouchEnabled = false;
846+
touch_handle_cancel(display, nullptr);
847+
}
848+
829849
display->pointer_surface = NULL;
830850
if (display->cursor_surface)
831851
wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
832852
}
833853

854+
static void
855+
touch_handle_motion(void *data, struct wl_touch *,
856+
uint32_t, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
834857
static void
835858
pointer_handle_motion(void *data, struct wl_pointer *,
836-
uint32_t, wl_fixed_t sx, wl_fixed_t sy)
859+
uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
837860
{
838861
struct display* display = (struct display*)data;
839862
struct input_event event[5];
@@ -851,6 +874,15 @@ pointer_handle_motion(void *data, struct wl_pointer *,
851874
ALOGE("%s:%d error in touch clock_gettime: %s",
852875
__FILE__, __LINE__, strerror(errno));
853876
}
877+
878+
display->pointer_surface_sx = sx;
879+
display->pointer_surface_sy = sy;
880+
881+
if (display->fakeTouchEnabled) {
882+
touch_handle_motion(display, nullptr, time, FAKE_TOUCH_ID, sx, sy);
883+
return;
884+
}
885+
854886
x = wl_fixed_to_int(sx);
855887
y = wl_fixed_to_int(sy);
856888
if (display->scale != 1) {
@@ -899,6 +931,17 @@ handle_relative_motion(void *data, struct zwp_relative_pointer_v1*,
899931
__FILE__, __LINE__, strerror(errno));
900932
}
901933

934+
if (display->pointer_surface) {
935+
display->pointer_surface_sx += dx;
936+
display->pointer_surface_sy += dy;
937+
938+
if (display->fakeTouchEnabled) {
939+
touch_handle_motion(display, nullptr, 0, FAKE_TOUCH_ID,
940+
display->pointer_surface_sx, display->pointer_surface_sy);
941+
return;
942+
}
943+
}
944+
902945
ADD_EVENT(EV_REL, REL_X, (int)acc_x);
903946
ADD_EVENT(EV_REL, REL_Y, (int)acc_y);
904947
ADD_EVENT(EV_SYN, SYN_REPORT, 0);
@@ -911,9 +954,16 @@ handle_relative_motion(void *data, struct zwp_relative_pointer_v1*,
911954
ALOGE("Failed to write event for InputFlinger: %s", strerror(errno));
912955
}
913956

957+
static void
958+
touch_handle_down(void *data, struct wl_touch *,
959+
uint32_t, uint32_t, struct wl_surface *surface,
960+
int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
961+
static void
962+
touch_handle_up(void *data, struct wl_touch *,
963+
uint32_t, uint32_t, int32_t id);
914964
static void
915965
pointer_handle_button(void *data, struct wl_pointer *,
916-
uint32_t, uint32_t, uint32_t button,
966+
uint32_t serial, uint32_t time, uint32_t button,
917967
uint32_t state)
918968
{
919969
struct display* display = (struct display*)data;
@@ -931,6 +981,39 @@ pointer_handle_button(void *data, struct wl_pointer *,
931981
ALOGE("%s:%d error in touch clock_gettime: %s",
932982
__FILE__, __LINE__, strerror(errno));
933983
}
984+
985+
// pointer fake to touch if no touch device
986+
bool fake_touch = false;
987+
// force fake touch even if have a touch device
988+
const bool force_fake_touch = property_get_bool("persist.waydroid.force_fake_touch_global", false);
989+
990+
if (force_fake_touch) {
991+
fake_touch = true;
992+
} else {
993+
fake_touch = !display->touch && property_get_bool("persist.waydroid.fake_touch_global", false);
994+
}
995+
996+
ALOGI("Pointer button event: button=%u, state=%u, fakeTouch=%d, pointer_surface=%p",
997+
button, state, fake_touch, display->pointer_surface);
998+
999+
if (button == BTN_LEFT && fake_touch) {
1000+
const bool fake_touch = property_get_bool("persist.waydroid.fake_touch_global", false);
1001+
// Ensure the config can be changed at runtime
1002+
if (fake_touch) {
1003+
// to touch event
1004+
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1005+
display->fakeTouchEnabled = true;
1006+
touch_handle_down(display, nullptr, serial, time,
1007+
display->pointer_surface, FAKE_TOUCH_ID,
1008+
display->pointer_surface_sx, display->pointer_surface_sy);
1009+
} else {
1010+
display->fakeTouchEnabled = false;
1011+
touch_handle_up(display, nullptr, serial, time, FAKE_TOUCH_ID);
1012+
}
1013+
return;
1014+
}
1015+
}
1016+
9341017
ADD_EVENT(EV_KEY, button, state);
9351018
ADD_EVENT(EV_SYN, SYN_REPORT, 0);
9361019

@@ -1064,6 +1147,8 @@ touch_handle_down(void *data, struct wl_touch *,
10641147
int x, y;
10651148
unsigned int res, n = 0;
10661149

1150+
ALOGI("Touch down event: id=%d, x=%f, y=%f", id, wl_fixed_to_double(x_w), wl_fixed_to_double(y_w));
1151+
10671152
if (ensure_pipe(display, INPUT_TOUCH))
10681153
return;
10691154

@@ -1103,6 +1188,8 @@ touch_handle_up(void *data, struct wl_touch *,
11031188
struct timespec rt;
11041189
unsigned int res, n = 0;
11051190

1191+
ALOGI("Touch up event: id=%d", id);
1192+
11061193
if (ensure_pipe(display, INPUT_TOUCH))
11071194
return;
11081195

@@ -1261,6 +1348,8 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t wl_caps)
12611348
{
12621349
struct display *d = (struct display*)data;
12631350
enum wl_seat_capability caps = (enum wl_seat_capability) wl_caps;
1351+
bool fakeTouch = false;
1352+
d->fakeTouchEnabled = false;
12641353

12651354
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
12661355
d->pointer = wl_seat_get_pointer(seat);
@@ -1271,6 +1360,8 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t wl_caps)
12711360
mkfifo(INPUT_PIPE_NAME[INPUT_POINTER], S_IRWXO | S_IRWXG | S_IRWXU);
12721361
chown(INPUT_PIPE_NAME[INPUT_POINTER], 1000, 1000);
12731362
wl_pointer_add_listener(d->pointer, &pointer_listener, d);
1363+
1364+
fakeTouch = !(wl_caps & WL_SEAT_CAPABILITY_TOUCH);
12741365
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
12751366
remove(INPUT_PIPE_NAME[INPUT_POINTER]);
12761367
wl_pointer_destroy(d->pointer);
@@ -1303,6 +1394,15 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t wl_caps)
13031394
wl_touch_destroy(d->touch);
13041395
d->touch = NULL;
13051396
}
1397+
1398+
if (fakeTouch) {
1399+
assert(!d->touch);
1400+
d->input_fd[INPUT_TOUCH] = -1;
1401+
mkfifo(INPUT_PIPE_NAME[INPUT_TOUCH], S_IRWXO | S_IRWXG | S_IRWXU);
1402+
chown(INPUT_PIPE_NAME[INPUT_TOUCH], 1000, 1000);
1403+
for (int i = 0; i < MAX_TOUCHPOINTS; i++)
1404+
d->touch_id[i] = -1;
1405+
}
13061406
}
13071407

13081408
static void

hwcomposer/wayland-hwc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,19 @@ struct display {
141141
std::mutex windowsMutex;
142142
std::map<int, struct wl_surface *> touch_surfaces;
143143
struct wl_surface *pointer_surface;
144+
// for fake touch event
145+
wl_fixed_t pointer_surface_sx;
146+
wl_fixed_t pointer_surface_sy;
144147
struct wl_surface *cursor_surface;
145148
struct wp_viewport *cursor_viewport;
146149
struct wl_surface *tablet_surface;
147150
std::list<struct zwp_tablet_tool_v2 *> tablet_tools;
148151
std::map<struct zwp_tablet_tool_v2 *, uint16_t> tablet_tools_evt;
149152
uint32_t keyboard_enter_serial;
150153
std::string clipboard;
154+
// for fake touch
155+
bool fakeTouchEnabled = false;
156+
bool fakeTouch = false;
151157

152158
EGLDisplay egl_dpy;
153159
std::list<std::function<void()>> egl_work_queue;

0 commit comments

Comments
 (0)